Contiki 3.x
tsch.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, 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 implementation.
36  * Does not use any RDC layer. Should be used with nordc.
37  * \author
38  * Simon Duquennoy <simonduq@sics.se>
39  * Beshr Al Nahas <beshr@sics.se>
40  *
41  */
42 
43 #include "contiki.h"
44 #include "dev/radio.h"
45 #include "net/netstack.h"
46 #include "net/packetbuf.h"
47 #include "net/queuebuf.h"
48 #include "net/mac/framer-802154.h"
49 #include "net/mac/tsch/tsch.h"
50 #include "net/mac/tsch/tsch-slot-operation.h"
51 #include "net/mac/tsch/tsch-queue.h"
53 #include "net/mac/tsch/tsch-log.h"
54 #include "net/mac/tsch/tsch-packet.h"
55 #include "net/mac/tsch/tsch-security.h"
56 #include "lib/random.h"
57 
58 #if FRAME802154_VERSION < FRAME802154_IEEE802154E_2012
59 #error TSCH: FRAME802154_VERSION must be at least FRAME802154_IEEE802154E_2012
60 #endif
61 
62 #if TSCH_LOG_LEVEL >= 1
63 #define DEBUG DEBUG_PRINT
64 #else /* TSCH_LOG_LEVEL */
65 #define DEBUG DEBUG_NONE
66 #endif /* TSCH_LOG_LEVEL */
67 #include "net/net-debug.h"
68 
69 /* Use to collect link statistics even on Keep-Alive, even though they were
70  * not sent from an upper layer and don't have a valid packet_sent callback */
71 #ifndef TSCH_LINK_NEIGHBOR_CALLBACK
72 void uip_ds6_link_neighbor_callback(int status, int numtx);
73 #define TSCH_LINK_NEIGHBOR_CALLBACK(dest, status, num) uip_ds6_link_neighbor_callback(status, num)
74 #endif /* TSCH_LINK_NEIGHBOR_CALLBACK */
75 
76 /* 802.15.4 duplicate frame detection */
77 struct seqno {
78  linkaddr_t sender;
79  uint8_t seqno;
80 };
81 
82 /* Size of the sequence number history */
83 #ifdef NETSTACK_CONF_MAC_SEQNO_HISTORY
84 #define MAX_SEQNOS NETSTACK_CONF_MAC_SEQNO_HISTORY
85 #else /* NETSTACK_CONF_MAC_SEQNO_HISTORY */
86 #define MAX_SEQNOS 8
87 #endif /* NETSTACK_CONF_MAC_SEQNO_HISTORY */
88 
89 /* Seqno history */
90 static struct seqno received_seqnos[MAX_SEQNOS];
91 
92 /* Let TSCH select a time source with no help of an upper layer.
93  * We do so using statistics from incoming EBs */
94 #if TSCH_AUTOSELECT_TIME_SOURCE
95 int best_neighbor_eb_count;
96 struct eb_stat {
97  int rx_count;
98  int jp;
99 };
100 NBR_TABLE(struct eb_stat, eb_stats);
101 #endif /* TSCH_AUTOSELECT_TIME_SOURCE */
102 
103 /* TSCH channel hopping sequence */
104 uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN];
105 struct asn_divisor_t tsch_hopping_sequence_length;
106 
107 /* Default TSCH timeslot timing (in micro-second) */
108 static const uint16_t tsch_default_timing_us[tsch_ts_elements_count] = {
109  TSCH_DEFAULT_TS_CCA_OFFSET,
110  TSCH_DEFAULT_TS_CCA,
111  TSCH_DEFAULT_TS_TX_OFFSET,
112  TSCH_DEFAULT_TS_RX_OFFSET,
113  TSCH_DEFAULT_TS_RX_ACK_DELAY,
114  TSCH_DEFAULT_TS_TX_ACK_DELAY,
115  TSCH_DEFAULT_TS_RX_WAIT,
116  TSCH_DEFAULT_TS_ACK_WAIT,
117  TSCH_DEFAULT_TS_RX_TX,
118  TSCH_DEFAULT_TS_MAX_ACK,
119  TSCH_DEFAULT_TS_MAX_TX,
120  TSCH_DEFAULT_TS_TIMESLOT_LENGTH,
121 };
122 /* TSCH timeslot timing (in rtimer ticks) */
123 rtimer_clock_t tsch_timing[tsch_ts_elements_count];
124 
125 #if LINKADDR_SIZE == 8
126 /* 802.15.4 broadcast MAC address */
127 const linkaddr_t tsch_broadcast_address = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
128 /* Address used for the EB virtual neighbor queue */
129 const linkaddr_t tsch_eb_address = { { 0, 0, 0, 0, 0, 0, 0, 0 } };
130 #else /* LINKADDR_SIZE == 8 */
131 const linkaddr_t tsch_broadcast_address = { { 0xff, 0xff } };
132 const linkaddr_t tsch_eb_address = { { 0, 0 } };
133 #endif /* LINKADDR_SIZE == 8 */
134 
135 /* Is TSCH started? */
136 int tsch_is_started = 0;
137 /* Has TSCH initialization failed? */
138 int tsch_is_initialized = 0;
139 /* Are we coordinator of the TSCH network? */
140 int tsch_is_coordinator = 0;
141 /* Are we associated to a TSCH network? */
142 int tsch_is_associated = 0;
143 /* Is the PAN running link-layer security? */
144 int tsch_is_pan_secured = LLSEC802154_ENABLED;
145 /* The current Absolute Slot Number (ASN) */
146 struct asn_t current_asn;
147 /* Device rank or join priority:
148  * For PAN coordinator: 0 -- lower is better */
149 uint8_t tsch_join_priority;
150 /* The current TSCH sequence number, used for both data and EBs */
151 static uint8_t tsch_packet_seqno = 0;
152 /* Current period for EB output */
153 static clock_time_t tsch_current_eb_period;
154 
155 /* timer for sending keepalive messages */
156 static struct ctimer keepalive_timer;
157 
158 /* TSCH processes and protothreads */
159 PT_THREAD(tsch_scan(struct pt *pt));
160 PROCESS(tsch_process, "TSCH: main process");
161 PROCESS(tsch_send_eb_process, "TSCH: send EB process");
162 PROCESS(tsch_pending_events_process, "TSCH: pending events process");
163 
164 /* Other function prototypes */
165 static void packet_input(void);
166 
167 /* Getters and setters */
168 
169 /*---------------------------------------------------------------------------*/
170 void
171 tsch_set_coordinator(int enable)
172 {
173  tsch_is_coordinator = enable;
174  tsch_set_eb_period(TSCH_EB_PERIOD);
175 }
176 /*---------------------------------------------------------------------------*/
177 void
178 tsch_set_pan_secured(int enable)
179 {
180  tsch_is_pan_secured = LLSEC802154_ENABLED && enable;
181 }
182 /*---------------------------------------------------------------------------*/
183 void
184 tsch_set_join_priority(uint8_t jp)
185 {
186  tsch_join_priority = jp;
187 }
188 /*---------------------------------------------------------------------------*/
189 void
190 tsch_set_eb_period(uint32_t period)
191 {
192  tsch_current_eb_period = period;
193 }
194 /*---------------------------------------------------------------------------*/
195 static void
196 tsch_reset(void)
197 {
198  int i;
199  frame802154_set_pan_id(0xffff);
200  /* First make sure pending packet callbacks are sent etc */
201  process_post_synch(&tsch_pending_events_process, PROCESS_EVENT_POLL, NULL);
202  /* Reset neighbor queues */
203  tsch_queue_reset();
204  /* Remove unused neighbors */
205  tsch_queue_free_unused_neighbors();
206  tsch_queue_update_time_source(NULL);
207  /* Initialize global variables */
208  tsch_join_priority = 0xff;
209  ASN_INIT(current_asn, 0, 0);
210  current_link = NULL;
211  /* Reset timeslot timing to defaults */
212  for(i = 0; i < tsch_ts_elements_count; i++) {
213  tsch_timing[i] = US_TO_RTIMERTICKS(tsch_default_timing_us[i]);
214  }
215 #ifdef TSCH_CALLBACK_LEAVING_NETWORK
216  TSCH_CALLBACK_LEAVING_NETWORK();
217 #endif
218 #if TSCH_AUTOSELECT_TIME_SOURCE
219  best_neighbor_eb_count = 0;
220  nbr_table_register(eb_stats, NULL);
221  tsch_set_eb_period(TSCH_EB_PERIOD);
222 #endif
223 }
224 
225 /* TSCH keep-alive functions */
226 
227 /*---------------------------------------------------------------------------*/
228 /* Tx callback for keepalive messages */
229 static void
230 keepalive_packet_sent(void *ptr, int status, int transmissions)
231 {
232 #ifdef TSCH_LINK_NEIGHBOR_CALLBACK
233  TSCH_LINK_NEIGHBOR_CALLBACK(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), status, transmissions);
234 #endif
235  PRINTF("TSCH: KA sent to %u, st %d-%d\n",
236  TSCH_LOG_ID_FROM_LINKADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER)), status, transmissions);
237  tsch_schedule_keepalive();
238 }
239 /*---------------------------------------------------------------------------*/
240 /* Prepare and send a keepalive message */
241 static void
242 keepalive_send()
243 {
244  if(tsch_is_associated) {
245  struct tsch_neighbor *n = tsch_queue_get_time_source();
246  /* Simply send an empty packet */
247  packetbuf_clear();
248  packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &n->addr);
249  NETSTACK_LLSEC.send(keepalive_packet_sent, NULL);
250  PRINTF("TSCH: sending KA to %u\n",
251  TSCH_LOG_ID_FROM_LINKADDR(&n->addr));
252  }
253 }
254 /*---------------------------------------------------------------------------*/
255 /* Set ctimer to send a keepalive message after expiration of TSCH_KEEPALIVE_TIMEOUT */
256 void
257 tsch_schedule_keepalive()
258 {
259  /* Pick a delay in the range [TSCH_KEEPALIVE_TIMEOUT*0.9, TSCH_KEEPALIVE_TIMEOUT[ */
260  if(!tsch_is_coordinator && tsch_is_associated) {
261  unsigned long delay = (TSCH_KEEPALIVE_TIMEOUT - TSCH_KEEPALIVE_TIMEOUT / 10)
262  + random_rand() % (TSCH_KEEPALIVE_TIMEOUT / 10);
263  ctimer_set(&keepalive_timer, delay, keepalive_send, NULL);
264  }
265 }
266 /*---------------------------------------------------------------------------*/
267 static void
268 eb_input(struct input_packet *current_input)
269 {
270  /* PRINTF("TSCH: EB received\n"); */
271  frame802154_t frame;
272  /* Verify incoming EB (does its ASN match our Rx time?),
273  * and update our join priority. */
274  struct ieee802154_ies eb_ies;
275 
276  if(tsch_packet_parse_eb(current_input->payload, current_input->len,
277  &frame, &eb_ies, NULL, 1)) {
278  /* PAN ID check and authentication done at rx time */
279 
280 #if TSCH_AUTOSELECT_TIME_SOURCE
281  if(!tsch_is_coordinator) {
282  /* Maintain EB received counter for every neighbor */
283  struct eb_stat *stat = (struct eb_stat *)nbr_table_get_from_lladdr(eb_stats, &frame.src_addr);
284  if(stat == NULL) {
285  stat = (struct eb_stat *)nbr_table_add_lladdr(eb_stats, &frame.src_addr);
286  }
287  if(stat != NULL) {
288  stat->rx_count++;
289  stat->jp = eb_ies.join_priority;
290  best_neighbor_eb_count = MAX(best_neighbor_eb_count, stat->rx_count);
291  }
292  /* Select best time source */
293  struct eb_stat *best_stat = NULL;
294  stat = nbr_table_head(eb_stats);
295  while(stat != NULL) {
296  /* Is neighbor eligible as a time source? */
297  if(stat->rx_count > best_neighbor_eb_count / 2) {
298  if(best_stat == NULL ||
299  stat->jp < best_stat->jp) {
300  best_stat = stat;
301  }
302  }
303  stat = nbr_table_next(eb_stats, stat);
304  }
305  /* Update time source */
306  if(best_stat != NULL) {
307  tsch_queue_update_time_source(nbr_table_get_lladdr(eb_stats, best_stat));
308  tsch_join_priority = best_stat->jp + 1;
309  }
310  }
311 #endif
312 
313  struct tsch_neighbor *n = tsch_queue_get_time_source();
314  /* Did the EB come from our time source? */
315  if(n != NULL && linkaddr_cmp((linkaddr_t *)&frame.src_addr, &n->addr)) {
316  /* Check for ASN drift */
317  int32_t asn_diff = ASN_DIFF(current_input->rx_asn, eb_ies.ie_asn);
318  if(asn_diff != 0) {
319  /* We disagree with our time source's ASN -- leave the network */
320  PRINTF("TSCH:! ASN drifted by %ld, leaving the network\n", asn_diff);
321  tsch_disassociate();
322  }
323 
324  if(eb_ies.ie_join_priority >= TSCH_MAX_JOIN_PRIORITY) {
325  /* Join priority unacceptable. Leave network. */
326  PRINTF("TSCH:! EB JP too high %u, leaving the network\n",
327  eb_ies.ie_join_priority);
328  tsch_disassociate();
329  } else {
330 #if TSCH_AUTOSELECT_TIME_SOURCE
331  /* Update join priority */
332  if(tsch_join_priority != eb_ies.ie_join_priority + 1) {
333  PRINTF("TSCH: update JP from EB %u -> %u\n",
334  tsch_join_priority, eb_ies.ie_join_priority + 1);
335  tsch_join_priority = eb_ies.ie_join_priority + 1;
336  }
337 #endif /* TSCH_AUTOSELECT_TIME_SOURCE */
338  }
339  }
340  }
341 }
342 
343 /*---------------------------------------------------------------------------*/
344 /* Process pending input packet(s) */
345 static void
346 tsch_rx_process_pending()
347 {
348  int16_t input_index;
349  /* Loop on accessing (without removing) a pending input packet */
350  while((input_index = ringbufindex_peek_get(&input_ringbuf)) != -1) {
351  struct input_packet *current_input = &input_array[input_index];
352  frame802154_t frame;
353  uint8_t ret = frame802154_parse(current_input->payload, current_input->len, &frame);
354  int is_data = ret && frame.fcf.frame_type == FRAME802154_DATAFRAME;
355  int is_eb = ret
356  && frame.fcf.frame_version == FRAME802154_IEEE802154E_2012
357  && frame.fcf.frame_type == FRAME802154_BEACONFRAME;
358 
359  if(is_data) {
360  /* Skip EBs and other control messages */
361  /* Copy to packetbuf for processing */
362  packetbuf_copyfrom(current_input->payload, current_input->len);
363  packetbuf_set_attr(PACKETBUF_ATTR_RSSI, current_input->rssi);
364  }
365 
366  /* Remove input from ringbuf */
367  ringbufindex_get(&input_ringbuf);
368 
369  if(is_data) {
370  /* Pass to upper layers */
371  packet_input();
372  } else if(is_eb) {
373  eb_input(current_input);
374  }
375  }
376 }
377 
378 /*---------------------------------------------------------------------------*/
379 /* Pass sent packets to upper layer */
380 static void
381 tsch_tx_process_pending()
382 {
383  int16_t dequeued_index;
384  /* Loop on accessing (without removing) a pending input packet */
385  while((dequeued_index = ringbufindex_peek_get(&dequeued_ringbuf)) != -1) {
386  struct tsch_packet *p = dequeued_array[dequeued_index];
387  /* Put packet into packetbuf for packet_sent callback */
388  queuebuf_to_packetbuf(p->qb);
389  /* Call packet_sent callback */
390  mac_call_sent_callback(p->sent, p->ptr, p->ret, p->transmissions);
391  /* Free packet queuebuf */
392  tsch_queue_free_packet(p);
393  /* Free all unused neighbors */
394  tsch_queue_free_unused_neighbors();
395  /* Remove dequeued packet from ringbuf */
396  ringbufindex_get(&dequeued_ringbuf);
397  }
398 }
399 /*---------------------------------------------------------------------------*/
400 /* Setup TSCH as a coordinator */
401 static void
402 tsch_start_coordinator(void)
403 {
404  frame802154_set_pan_id(IEEE802154_PANID);
405  /* Initialize hopping sequence as default */
406  memcpy(tsch_hopping_sequence, TSCH_DEFAULT_HOPPING_SEQUENCE, sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE));
407  ASN_DIVISOR_INIT(tsch_hopping_sequence_length, sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE));
408 #if TSCH_SCHEDULE_WITH_6TISCH_MINIMAL
409  tsch_schedule_create_minimal();
410 #endif
411 
412  tsch_is_associated = 1;
413  tsch_join_priority = 0;
414 
415  PRINTF("TSCH: starting as coordinator, PAN ID %x, asn-%x.%lx\n",
416  frame802154_get_pan_id(), current_asn.ms1b, current_asn.ls4b);
417 
418  /* Start slot operation */
419  tsch_slot_operation_sync(RTIMER_NOW(), &current_asn);
420 }
421 /*---------------------------------------------------------------------------*/
422 /* Leave the TSCH network */
423 void
424 tsch_disassociate(void)
425 {
426  if(tsch_is_associated == 1) {
427  tsch_is_associated = 0;
428  process_post(&tsch_process, PROCESS_EVENT_POLL, NULL);
429  PRINTF("TSCH: leaving the network\n");
430  }
431 }
432 /*---------------------------------------------------------------------------*/
433 /* Attempt to associate to a network form an incoming EB */
434 static int
435 tsch_associate(const struct input_packet *input_eb, rtimer_clock_t timestamp)
436 {
437  frame802154_t frame;
438  struct ieee802154_ies ies;
439  uint8_t hdrlen;
440  int i;
441 
442  if(input_eb == NULL || tsch_packet_parse_eb(input_eb->payload, input_eb->len,
443  &frame, &ies, &hdrlen, 0) == 0) {
444  PRINTF("TSCH:! failed to parse EB (len %u)\n", input_eb->len);
445  return 0;
446  }
447 
448  current_asn = ies.ie_asn;
449  tsch_join_priority = ies.ie_join_priority + 1;
450 
451 #if TSCH_JOIN_SECURED_ONLY
452  if(frame.fcf.security_enabled == 0) {
453  PRINTF("TSCH:! parse_eb: EB is not secured\n");
454  return 0;
455  }
456 #endif /* TSCH_JOIN_SECURED_ONLY */
457 
458 #if LLSEC802154_ENABLED
459  if(!tsch_security_parse_frame(input_eb->payload, hdrlen,
460  input_eb->len - hdrlen - tsch_security_mic_len(&frame),
461  &frame, (linkaddr_t*)&frame.src_addr, &current_asn)) {
462  PRINTF("TSCH:! parse_eb: failed to authenticate\n");
463  return 0;
464  }
465 #endif /* LLSEC802154_ENABLED */
466 
467 #if !LLSEC802154_ENABLED
468  if(frame.fcf.security_enabled == 1) {
469  PRINTF("TSCH:! parse_eb: we do not support security, but EB is secured\n");
470  return 0;
471  }
472 #endif /* !LLSEC802154_ENABLED */
473 
474 #if TSCH_JOIN_MY_PANID_ONLY
475  /* Check if the EB comes from the PAN ID we expect */
476  if(frame.src_pid != IEEE802154_PANID) {
477  PRINTF("TSCH:! parse_eb: PAN ID %x != %x\n", frame.src_pid, IEEE802154_PANID);
478  return 0;
479  }
480 #endif /* TSCH_JOIN_MY_PANID_ONLY */
481 
482  /* There was no join priority (or 0xff) in the EB, do not join */
483  if(ies.ie_join_priority == 0xff) {
484  PRINTF("TSCH:! parse_eb: no join priority\n");
485  return 0;
486  }
487 
488  /* TSCH timeslot timing */
489  for(i = 0; i < tsch_ts_elements_count; i++) {
490  if(ies.ie_tsch_timeslot_id == 0) {
491  tsch_timing[i] = US_TO_RTIMERTICKS(tsch_default_timing_us[i]);
492  } else {
493  tsch_timing[i] = US_TO_RTIMERTICKS(ies.ie_tsch_timeslot[i]);
494  }
495  }
496 
497  /* TSCH hopping sequence */
498  if(ies.ie_channel_hopping_sequence_id == 0) {
499  memcpy(tsch_hopping_sequence, TSCH_DEFAULT_HOPPING_SEQUENCE, sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE));
500  ASN_DIVISOR_INIT(tsch_hopping_sequence_length, sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE));
501  } else {
502  if(ies.ie_hopping_sequence_len <= sizeof(tsch_hopping_sequence)) {
503  memcpy(tsch_hopping_sequence, ies.ie_hopping_sequence_list, ies.ie_hopping_sequence_len);
504  ASN_DIVISOR_INIT(tsch_hopping_sequence_length, ies.ie_hopping_sequence_len);
505  } else {
506  PRINTF("TSCH:! parse_eb: hopping sequence too long (%u)\n", ies.ie_hopping_sequence_len);
507  return 0;
508  }
509  }
510 
511 #if TSCH_CHECK_TIME_AT_ASSOCIATION > 0
512  /* Divide by 4k and multiply again to avoid integer overflow */
513  uint32_t expected_asn = 4096 * TSCH_CLOCK_TO_SLOTS(clock_time() / 4096, tsch_timing_timeslot_length); /* Expected ASN based on our current time*/
514  int32_t asn_threshold = TSCH_CHECK_TIME_AT_ASSOCIATION * 60ul * TSCH_CLOCK_TO_SLOTS(CLOCK_SECOND, tsch_timing_timeslot_length);
515  int32_t asn_diff = (int32_t)current_asn.ls4b - expected_asn;
516  if(asn_diff > asn_threshold) {
517  PRINTF("TSCH:! EB ASN rejected %lx %lx %ld\n",
518  current_asn.ls4b, expected_asn, asn_diff);
519  return 0;
520  }
521 #endif
522 
523 #if TSCH_INIT_SCHEDULE_FROM_EB
524  /* Create schedule */
525  if(ies.ie_tsch_slotframe_and_link.num_slotframes == 0) {
526 #if TSCH_SCHEDULE_WITH_6TISCH_MINIMAL
527  PRINTF("TSCH: parse_eb: no schedule, setting up minimal schedule\n");
528  tsch_schedule_create_minimal();
529 #else
530  PRINTF("TSCH: parse_eb: no schedule\n");
531 #endif
532  } else {
533  /* First, empty current schedule */
534  tsch_schedule_remove_all_slotframes();
535  /* We support only 0 or 1 slotframe in this IE */
536  int num_links = ies.ie_tsch_slotframe_and_link.num_links;
537  if(num_links <= FRAME802154E_IE_MAX_LINKS) {
538  int i;
539  struct tsch_slotframe *sf = tsch_schedule_add_slotframe(
540  ies.ie_tsch_slotframe_and_link.slotframe_handle,
541  ies.ie_tsch_slotframe_and_link.slotframe_size);
542  for(i = 0; i < num_links; i++) {
543  tsch_schedule_add_link(sf,
544  ies.ie_tsch_slotframe_and_link.links[i].link_options,
545  LINK_TYPE_ADVERTISING, &tsch_broadcast_address,
546  ies.ie_tsch_slotframe_and_link.links[i].timeslot, ies.ie_tsch_slotframe_and_link.links[i].channel_offset);
547  }
548  } else {
549  PRINTF("TSCH:! parse_eb: too many links in schedule (%u)\n", num_links);
550  return 0;
551  }
552  }
553 #endif /* TSCH_INIT_SCHEDULE_FROM_EB */
554 
555  if(tsch_join_priority < TSCH_MAX_JOIN_PRIORITY) {
556  struct tsch_neighbor *n;
557 
558  /* Add coordinator to list of neighbors, lock the entry */
559  n = tsch_queue_add_nbr((linkaddr_t *)&frame.src_addr);
560 
561  if(n != NULL) {
562  tsch_queue_update_time_source((linkaddr_t *)&frame.src_addr);
563 
564 #ifdef TSCH_CALLBACK_JOINING_NETWORK
565  TSCH_CALLBACK_JOINING_NETWORK();
566 #endif
567 
568  /* Set PANID */
569  frame802154_set_pan_id(frame.src_pid);
570 
571  /* Synchronize on EB */
572  tsch_slot_operation_sync(timestamp - tsch_timing[tsch_ts_tx_offset], &current_asn);
573 
574  /* Update global flags */
575  tsch_is_associated = 1;
576  tsch_is_pan_secured = frame.fcf.security_enabled;
577 
578  /* Association done, schedule keepalive messages */
579  tsch_schedule_keepalive();
580 
581  PRINTF("TSCH: association done, sec %u, PAN ID %x, asn-%x.%lx, jp %u, timeslot id %u, hopping id %u, slotframe len %u with %u links, from ",
582  tsch_is_pan_secured,
583  frame.src_pid,
584  current_asn.ms1b, current_asn.ls4b, tsch_join_priority,
585  ies.ie_tsch_timeslot_id,
586  ies.ie_channel_hopping_sequence_id,
587  ies.ie_tsch_slotframe_and_link.slotframe_size,
588  ies.ie_tsch_slotframe_and_link.num_links);
589  PRINTLLADDR((const uip_lladdr_t *)&frame.src_addr);
590  PRINTF("\n");
591 
592  return 1;
593  }
594  }
595  PRINTF("TSCH:! did not associate.\n");
596  return 0;
597 }
598 
599 /* Processes and protothreads used by TSCH */
600 
601 /*---------------------------------------------------------------------------*/
602 /* Scanning protothread, called by tsch_process:
603  * Listen to different channels, and when receiving an EB,
604  * attempt to associate.
605  */
606 PT_THREAD(tsch_scan(struct pt *pt))
607 {
608  PT_BEGIN(pt);
609 
610  static struct input_packet input_eb;
611  static struct etimer scan_timer;
612 
613  ASN_INIT(current_asn, 0, 0);
614 
615  etimer_set(&scan_timer, CLOCK_SECOND / TSCH_ASSOCIATION_POLL_FREQUENCY);
616 
617  while(!tsch_is_associated && !tsch_is_coordinator) {
618  /* Hop to any channel offset */
619  static int current_channel = 0;
620  /* Time when we started scanning on current_channel */
621  static clock_time_t current_channel_since = 0;
622 
623  /* We are not coordinator, try to associate */
624  rtimer_clock_t t0;
625  int is_packet_pending = 0;
626  clock_time_t now_seconds = clock_seconds();
627 
628  /* Switch to a (new) channel for scanning */
629  if(current_channel == 0 || now_seconds != current_channel_since) {
630  /* Pick a channel at random in TSCH_JOIN_HOPPING_SEQUENCE */
631  uint8_t scan_channel = TSCH_JOIN_HOPPING_SEQUENCE[
632  random_rand() % sizeof(TSCH_JOIN_HOPPING_SEQUENCE)];
633  if(current_channel != scan_channel) {
634  NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, scan_channel);
635  current_channel = scan_channel;
636  PRINTF("TSCH: scanning on channel %u\n", scan_channel);
637  }
638  current_channel_since = now_seconds;
639  }
640 
641  /* Turn radio on and wait for EB */
642  NETSTACK_RADIO.on();
643 
644  is_packet_pending = NETSTACK_RADIO.pending_packet();
645  if(!is_packet_pending && NETSTACK_RADIO.receiving_packet()) {
646  /* If we are currently receiving a packet, wait until end of reception */
647  t0 = RTIMER_NOW();
648  BUSYWAIT_UNTIL_ABS((is_packet_pending = NETSTACK_RADIO.pending_packet()), t0, RTIMER_SECOND / 100);
649  }
650 
651  if(is_packet_pending) {
652  /* Save packet timestamp */
653  NETSTACK_RADIO.get_object(RADIO_PARAM_LAST_PACKET_TIMESTAMP, &t0, sizeof(rtimer_clock_t));
654 
655  /* Read packet */
656  input_eb.len = NETSTACK_RADIO.read(input_eb.payload, TSCH_PACKET_MAX_LEN);
657 
658  /* Parse EB and attempt to associate */
659  PRINTF("TSCH: association: received packet (%u bytes) on channel %u\n", input_eb.len, current_channel);
660 
661  tsch_associate(&input_eb, t0);
662  }
663 
664  if(tsch_is_associated) {
665  /* End of association, turn the radio off */
666  NETSTACK_RADIO.off();
667  } else if(!tsch_is_coordinator) {
668  /* Go back to scanning */
669  etimer_reset(&scan_timer);
670  PT_WAIT_UNTIL(pt, etimer_expired(&scan_timer));
671  }
672  }
673 
674  PT_END(pt);
675 }
676 
677 /*---------------------------------------------------------------------------*/
678 /* The main TSCH process */
679 PROCESS_THREAD(tsch_process, ev, data)
680 {
681  static struct pt scan_pt;
682 
683  PROCESS_BEGIN();
684 
685  while(1) {
686 
687  while(!tsch_is_associated) {
688  if(tsch_is_coordinator) {
689  /* We are coordinator, start operating now */
690  tsch_start_coordinator();
691  } else {
692  /* Start scanning, will attempt to join when receiving an EB */
693  PROCESS_PT_SPAWN(&scan_pt, tsch_scan(&scan_pt));
694  }
695  }
696 
697  /* We are part of a TSCH network, start slot operation */
698  tsch_slot_operation_start();
699 
700  /* Yield our main process. Slot operation will re-schedule itself
701  * as long as we are associated */
702  PROCESS_YIELD_UNTIL(!tsch_is_associated);
703 
704  /* Will need to re-synchronize */
705  tsch_reset();
706  }
707 
708  PROCESS_END();
709 }
710 
711 /*---------------------------------------------------------------------------*/
712 /* A periodic process to send TSCH Enhanced Beacons (EB) */
713 PROCESS_THREAD(tsch_send_eb_process, ev, data)
714 {
715  static struct etimer eb_timer;
716 
717  PROCESS_BEGIN();
718 
719  /* Wait until association */
720  etimer_set(&eb_timer, CLOCK_SECOND / 10);
721  while(!tsch_is_associated) {
723  etimer_reset(&eb_timer);
724  }
725 
726  /* Set an initial delay except for coordinator, which should send an EB asap */
727  if(!tsch_is_coordinator) {
728  etimer_set(&eb_timer, random_rand() % TSCH_EB_PERIOD);
730  }
731 
732  while(1) {
733  unsigned long delay;
734 
735  if(tsch_is_associated && tsch_current_eb_period > 0) {
736  /* Enqueue EB only if there isn't already one in queue */
737  if(tsch_queue_packet_count(&tsch_eb_address) == 0) {
738  int eb_len;
739  uint8_t hdr_len = 0;
740  uint8_t tsch_sync_ie_offset;
741  /* Prepare the EB packet and schedule it to be sent */
742  packetbuf_clear();
743  /* We don't use seqno 0 */
744  if(++tsch_packet_seqno == 0) {
745  tsch_packet_seqno++;
746  }
747  packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_BEACONFRAME);
748  packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, tsch_packet_seqno);
749 #if LLSEC802154_ENABLED
750  if(tsch_is_pan_secured) {
751  /* Set security level, key id and index */
752  packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, TSCH_SECURITY_KEY_SEC_LEVEL_EB);
753  packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, FRAME802154_1_BYTE_KEY_ID_MODE); /* Use 1-byte key index */
754  packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, TSCH_SECURITY_KEY_INDEX_EB);
755  }
756 #endif /* LLSEC802154_ENABLED */
757  eb_len = tsch_packet_create_eb(packetbuf_dataptr(), PACKETBUF_SIZE,
758  tsch_packet_seqno, &hdr_len, &tsch_sync_ie_offset);
759  if(eb_len != 0) {
760  struct tsch_packet *p;
761  packetbuf_set_datalen(eb_len);
762  /* Enqueue EB packet */
763  if(!(p = tsch_queue_add_packet(&tsch_eb_address, NULL, NULL))) {
764  PRINTF("TSCH:! could not enqueue EB packet\n");
765  } else {
766  PRINTF("TSCH: enqueue EB packet %u %u\n", eb_len, hdr_len);
767  p->tsch_sync_ie_offset = tsch_sync_ie_offset;
768  p->header_len = hdr_len;
769  }
770  }
771  }
772  }
773  if(tsch_current_eb_period > 0) {
774  /* Next EB transmission with a random delay
775  * within [tsch_current_eb_period*0.75, tsch_current_eb_period[ */
776  delay = (tsch_current_eb_period - tsch_current_eb_period / 4)
777  + random_rand() % (tsch_current_eb_period / 4);
778  } else {
779  delay = TSCH_EB_PERIOD;
780  }
781  etimer_set(&eb_timer, delay);
783  }
784  PROCESS_END();
785 }
786 
787 /*---------------------------------------------------------------------------*/
788 /* A process that is polled from interrupt and calls tx/rx input
789  * callbacks, outputs pending logs. */
790 PROCESS_THREAD(tsch_pending_events_process, ev, data)
791 {
792  PROCESS_BEGIN();
793  while(1) {
794  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
795  tsch_rx_process_pending();
796  tsch_tx_process_pending();
797  tsch_log_process_pending();
798  }
799  PROCESS_END();
800 }
801 
802 /* Functions from the Contiki MAC layer driver interface */
803 
804 /*---------------------------------------------------------------------------*/
805 static void
806 tsch_init(void)
807 {
808  radio_value_t radio_rx_mode;
809  radio_value_t radio_tx_mode;
810  rtimer_clock_t t;
811 
812  /* Radio Rx mode */
813  if(NETSTACK_RADIO.get_value(RADIO_PARAM_RX_MODE, &radio_rx_mode) != RADIO_RESULT_OK) {
814  printf("TSCH:! radio does not support getting RADIO_PARAM_RX_MODE. Abort init.\n");
815  return;
816  }
817  /* Disable radio in frame filtering */
818  radio_rx_mode &= ~RADIO_RX_MODE_ADDRESS_FILTER;
819  /* Unset autoack */
820  radio_rx_mode &= ~RADIO_RX_MODE_AUTOACK;
821  /* Set radio in poll mode */
822  radio_rx_mode |= RADIO_RX_MODE_POLL_MODE;
823  if(NETSTACK_RADIO.set_value(RADIO_PARAM_RX_MODE, radio_rx_mode) != RADIO_RESULT_OK) {
824  printf("TSCH:! radio does not support setting required RADIO_PARAM_RX_MODE. Abort init.\n");
825  return;
826  }
827 
828  /* Radio Tx mode */
829  if(NETSTACK_RADIO.get_value(RADIO_PARAM_TX_MODE, &radio_tx_mode) != RADIO_RESULT_OK) {
830  printf("TSCH:! radio does not support getting RADIO_PARAM_TX_MODE. Abort init.\n");
831  return;
832  }
833  /* Unset CCA */
834  radio_tx_mode &= ~RADIO_TX_MODE_SEND_ON_CCA;
835  if(NETSTACK_RADIO.set_value(RADIO_PARAM_TX_MODE, radio_tx_mode) != RADIO_RESULT_OK) {
836  printf("TSCH:! radio does not support setting required RADIO_PARAM_TX_MODE. Abort init.\n");
837  return;
838  }
839  /* Test setting channel */
840  if(NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, TSCH_DEFAULT_HOPPING_SEQUENCE[0]) != RADIO_RESULT_OK) {
841  printf("TSCH:! radio does not support setting channel. Abort init.\n");
842  return;
843  }
844  /* Test getting timestamp */
845  if(NETSTACK_RADIO.get_object(RADIO_PARAM_LAST_PACKET_TIMESTAMP, &t, sizeof(rtimer_clock_t)) != RADIO_RESULT_OK) {
846  printf("TSCH:! radio does not support getting last packet timestamp. Abort init.\n");
847  return;
848  }
849  /* Check max hopping sequence length vs default sequence length */
850  if(TSCH_HOPPING_SEQUENCE_MAX_LEN < sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)) {
851  printf("TSCH:! TSCH_HOPPING_SEQUENCE_MAX_LEN < sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE). Abort init.\n");
852  }
853 
854  /* Init TSCH sub-modules */
855  tsch_reset();
856  tsch_queue_init();
857  tsch_schedule_init();
858  tsch_log_init();
859  ringbufindex_init(&input_ringbuf, TSCH_MAX_INCOMING_PACKETS);
860  ringbufindex_init(&dequeued_ringbuf, TSCH_DEQUEUED_ARRAY_SIZE);
861 
862  tsch_is_initialized = 1;
863 
864 #if TSCH_AUTOSTART
865  /* Start TSCH operation.
866  * If TSCH_AUTOSTART is not set, one needs to call NETSTACK_MAC.on() to start TSCH. */
867  NETSTACK_MAC.on();
868 #endif /* TSCH_AUTOSTART */
869 }
870 /*---------------------------------------------------------------------------*/
871 /* Function send for TSCH-MAC, puts the packet in packetbuf in the MAC queue */
872 static void
873 send_packet(mac_callback_t sent, void *ptr)
874 {
875  int ret = MAC_TX_DEFERRED;
876  int packet_count_before;
877  int hdr_len = 0;
878  const linkaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
879 
880  if(!tsch_is_associated) {
881  if(!tsch_is_initialized) {
882  PRINTF("TSCH:! not initialized (see earlier logs), drop outgoing packet\n");
883  } else {
884  PRINTF("TSCH:! not associated, drop outgoing packet\n");
885  }
886  ret = MAC_TX_ERR;
887  mac_call_sent_callback(sent, ptr, ret, 1);
888  return;
889  }
890 
891  /* PACKETBUF_ATTR_MAC_SEQNO cannot be zero, due to a pecuilarity
892  in framer-802154.c. */
893  if(++tsch_packet_seqno == 0) {
894  tsch_packet_seqno++;
895  }
896 
897  /* Ask for ACK if we are sending anything other than broadcast */
898  if(!linkaddr_cmp(addr, &linkaddr_null)) {
899  packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
900  } else {
901  /* Broadcast packets shall be added to broadcast queue
902  * The broadcast address in Contiki is linkaddr_null which is equal
903  * to tsch_eb_address */
904  addr = &tsch_broadcast_address;
905  }
906 
907  packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME);
908  packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, tsch_packet_seqno);
909 
910 #if LLSEC802154_ENABLED
911  if(tsch_is_pan_secured) {
912  /* Set security level, key id and index */
913  packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, TSCH_SECURITY_KEY_SEC_LEVEL_OTHER);
914  packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, FRAME802154_1_BYTE_KEY_ID_MODE); /* Use 1-byte key index */
915  packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, TSCH_SECURITY_KEY_INDEX_OTHER);
916  }
917 #endif /* LLSEC802154_ENABLED */
918 
919  packet_count_before = tsch_queue_packet_count(addr);
920 
921  if((hdr_len = NETSTACK_FRAMER.create()) < 0) {
922  PRINTF("TSCH:! can't send packet due to framer error\n");
923  ret = MAC_TX_ERR;
924  } else {
925  struct tsch_packet *p;
926  /* Enqueue packet */
927  p = tsch_queue_add_packet(addr, sent, ptr);
928  if(p == NULL) {
929  PRINTF("TSCH:! can't send packet !tsch_queue_add_packet\n");
930  ret = MAC_TX_ERR;
931  } else {
932  p->header_len = hdr_len;
933  PRINTF("TSCH: send packet to %u with seqno %u, queue %u %u, len %u %u\n",
934  TSCH_LOG_ID_FROM_LINKADDR(addr), tsch_packet_seqno,
935  packet_count_before,
936  tsch_queue_packet_count(addr),
937  p->header_len,
938  queuebuf_datalen(p->qb));
939  (void)packet_count_before; /* Discard "variable set but unused" warning in case of TSCH_LOG_LEVEL of 0 */
940  }
941  }
942  if(ret != MAC_TX_DEFERRED) {
943  mac_call_sent_callback(sent, ptr, ret, 1);
944  }
945 }
946 /*---------------------------------------------------------------------------*/
947 static void
948 packet_input(void)
949 {
950  int frame_parsed = 1;
951 
952  frame_parsed = NETSTACK_FRAMER.parse();
953 
954  if(frame_parsed < 0) {
955  PRINTF("TSCH:! failed to parse %u\n", packetbuf_datalen());
956  } else {
957  int duplicate = 0;
958 
959  /* Seqno of 0xffff means no seqno */
960  if(packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO) != 0xffff) {
961  /* Check for duplicate packet by comparing the sequence number
962  of the incoming packet with the last few ones we saw. */
963  int i;
964  for(i = 0; i < MAX_SEQNOS; ++i) {
965  if(packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO) == received_seqnos[i].seqno &&
966  linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER),
967  &received_seqnos[i].sender)) {
968  /* Drop the packet. */
969  PRINTF("TSCH:! drop dup ll from %u seqno %u\n",
970  TSCH_LOG_ID_FROM_LINKADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER)),
971  packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
972  duplicate = 1;
973  }
974  }
975  if(!duplicate) {
976  for(i = MAX_SEQNOS - 1; i > 0; --i) {
977  memcpy(&received_seqnos[i], &received_seqnos[i - 1],
978  sizeof(struct seqno));
979  }
980  received_seqnos[0].seqno = packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO);
981  linkaddr_copy(&received_seqnos[0].sender,
982  packetbuf_addr(PACKETBUF_ADDR_SENDER));
983  }
984  }
985 
986  if(!duplicate) {
987  PRINTF("TSCH: received from %u with seqno %u\n",
988  TSCH_LOG_ID_FROM_LINKADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER)),
989  packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
990  NETSTACK_LLSEC.input();
991  }
992  }
993 }
994 /*---------------------------------------------------------------------------*/
995 static int
996 turn_on(void)
997 {
998  if(tsch_is_initialized == 1 && tsch_is_started == 0) {
999  tsch_is_started = 1;
1000  /* Process tx/rx callback and log messages whenever polled */
1001  process_start(&tsch_pending_events_process, NULL);
1002  /* periodically send TSCH EBs */
1003  process_start(&tsch_send_eb_process, NULL);
1004  /* try to associate to a network or start one if setup as coordinator */
1005  process_start(&tsch_process, NULL);
1006  PRINTF("TSCH: starting as %s\n", tsch_is_coordinator ? "coordinator" : "node");
1007  return 1;
1008  }
1009  return 0;
1010 }
1011 /*---------------------------------------------------------------------------*/
1012 static int
1013 turn_off(int keep_radio_on)
1014 {
1015  return 1;
1016 }
1017 /*---------------------------------------------------------------------------*/
1018 static unsigned short
1019 channel_check_interval(void)
1020 {
1021  return 0;
1022 }
1023 /*---------------------------------------------------------------------------*/
1024 const struct mac_driver tschmac_driver = {
1025  "TSCH",
1026  tsch_init,
1027  send_packet,
1028  packet_input,
1029  turn_on,
1030  turn_off,
1032 };
1033 /*---------------------------------------------------------------------------*/
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:158
uint8_t security_enabled
1 bit.
Definition: frame802154.h:148
uint16_t src_pid
Source PAN ID.
Definition: frame802154.h:201
Header file for the radio API
static uip_ds6_addr_t * addr
Pointer to a router list entry.
Definition: uip-nd6.c:124
frame802154_fcf_t fcf
Frame control field.
Definition: frame802154.h:198
#define RTIMER_NOW()
Get the current clock time.
Definition: rtimer.h:135
void packetbuf_clear(void)
Clear and reset the packetbuf.
Definition: packetbuf.c:76
CCIF clock_time_t clock_time(void)
Get the current clock time.
Definition: clock.c:41
uint8_t src_addr[8]
Source address.
Definition: frame802154.h:197
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition: etimer.c:177
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define PT_WAIT_UNTIL(pt, condition)
Block and wait until condition is true.
Definition: pt.h:147
A timer.
Definition: etimer.h:76
Private TSCH definitions (meant for use by TSCH implementation files only) ...
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
Definition: packetbuf.h:66
const linkaddr_t linkaddr_null
The null Rime address.
Definition: eth-conf.c:37
Header file for the Rime buffer (packetbuf) management
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
The MAC layer transmission could not be performed because of a fatal error.
Definition: mac.h:93
The MAC layer transmission could not be performed because of an error.
Definition: mac.h:89
A set of debugging macros for the netstack
void process_post_synch(struct process *p, process_event_t ev, process_data_t data)
Post a synchronous event to a process.
Definition: process.c:362
#define NULL
The null pointer.
802.3 address
Definition: uip.h:129
uint8_t frame_type
3 bit.
Definition: frame802154.h:147
int radio_value_t
Each radio has a set of parameters that designate the current configuration and state of the radio...
Definition: radio.h:88
#define RADIO_RX_MODE_ADDRESS_FILTER
The radio reception mode controls address filtering and automatic transmission of acknowledgements in...
Definition: radio.h:204
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
Definition: random.c:47
#define PT_THREAD(name_args)
Declaration of a protothread.
Definition: pt.h:99
The structure of a MAC protocol driver in Contiki.
Definition: mac.h:54
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:213
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
Definition: pt.h:114
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
int frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
Parses an input frame.
Definition: frame802154.c:465
#define RADIO_TX_MODE_SEND_ON_CCA
The radio transmission mode controls whether transmissions should be done using clear channel assessm...
Definition: radio.h:216
unsigned short(* channel_check_interval)(void)
Returns the channel check interval, expressed in clock_time_t ticks.
Definition: mac.h:73
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition: packetbuf.c:151
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
int packetbuf_copyfrom(const void *from, uint16_t len)
Copy from external data into the packetbuf.
Definition: packetbuf.c:85
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
#define PT_END(pt)
Declare the end of a protothread.
Definition: pt.h:126
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
Definition: packetbuf.c:170
Header file for the Rime queue buffer management
CCIF unsigned long clock_seconds(void)
Get the current value of the platform seconds.
Definition: clock.c:54
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two Rime addresses.
Definition: linkaddr.c:66
#define PROCESS_PT_SPAWN(pt, thread)
Spawn a protothread from the process.
Definition: process.h:211
#define PROCESS_WAIT_UNTIL(c)
Wait for a condition to occur.
Definition: process.h:192
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a Rime address.
Definition: linkaddr.c:60
uint8_t frame_version
2 bit.
Definition: frame802154.h:156
Parameters used by the frame802154_create() function.
Definition: frame802154.h:192
Include file for the Contiki low-layer network stack (NETSTACK)
void etimer_reset(struct etimer *et)
Reset an event timer with the same interval as was previously set.
Definition: etimer.c:192
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
A MAC framer for IEEE 802.15.4