Contiki-NG
tsch-slot-operation.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  * TSCH slot operation implementation, running from interrupt.
36  * \author
37  * Simon Duquennoy <simonduq@sics.se>
38  * Beshr Al Nahas <beshr@sics.se>
39  * Atis Elsts <atis.elsts@bristol.ac.uk>
40  *
41  */
42 
43 /**
44  * \addtogroup tsch
45  * @{
46 */
47 
48 #include "dev/radio.h"
49 #include "contiki.h"
50 #include "net/netstack.h"
51 #include "net/packetbuf.h"
52 #include "net/queuebuf.h"
54 #include "net/mac/tsch/tsch.h"
55 #if CONTIKI_TARGET_COOJA
56 #include "lib/simEnvChange.h"
57 #include "sys/cooja_mt.h"
58 #endif /* CONTIKI_TARGET_COOJA */
59 
60 #include "sys/log.h"
61 /* TSCH debug macros, i.e. to set LEDs or GPIOs on various TSCH
62  * timeslot events */
63 #ifndef TSCH_DEBUG_INIT
64 #define TSCH_DEBUG_INIT()
65 #endif
66 #ifndef TSCH_DEBUG_INTERRUPT
67 #define TSCH_DEBUG_INTERRUPT()
68 #endif
69 #ifndef TSCH_DEBUG_RX_EVENT
70 #define TSCH_DEBUG_RX_EVENT()
71 #endif
72 #ifndef TSCH_DEBUG_TX_EVENT
73 #define TSCH_DEBUG_TX_EVENT()
74 #endif
75 #ifndef TSCH_DEBUG_SLOT_START
76 #define TSCH_DEBUG_SLOT_START()
77 #endif
78 #ifndef TSCH_DEBUG_SLOT_END
79 #define TSCH_DEBUG_SLOT_END()
80 #endif
81 
82 /* Check if TSCH_MAX_INCOMING_PACKETS is power of two */
83 #if (TSCH_MAX_INCOMING_PACKETS & (TSCH_MAX_INCOMING_PACKETS - 1)) != 0
84 #error TSCH_MAX_INCOMING_PACKETS must be power of two
85 #endif
86 
87 /* Check if TSCH_DEQUEUED_ARRAY_SIZE is power of two and greater or equal to QUEUEBUF_NUM */
88 #if TSCH_DEQUEUED_ARRAY_SIZE < QUEUEBUF_NUM
89 #error TSCH_DEQUEUED_ARRAY_SIZE must be greater or equal to QUEUEBUF_NUM
90 #endif
91 #if (TSCH_DEQUEUED_ARRAY_SIZE & (TSCH_DEQUEUED_ARRAY_SIZE - 1)) != 0
92 #error TSCH_DEQUEUED_ARRAY_SIZE must be power of two
93 #endif
94 
95 /* Truncate received drift correction information to maximum half
96  * of the guard time (one fourth of TSCH_DEFAULT_TS_RX_WAIT) */
97 #define SYNC_IE_BOUND ((int32_t)US_TO_RTIMERTICKS(TSCH_DEFAULT_TS_RX_WAIT / 4))
98 
99 /* By default: check that rtimer runs at >=32kHz and use a guard time of 10us */
100 #if RTIMER_SECOND < (32 * 1024)
101 #error "TSCH: RTIMER_SECOND < (32 * 1024)"
102 #endif
103 #if CONTIKI_TARGET_COOJA
104 /* Use 0 usec guard time for Cooja Mote with a 1 MHz Rtimer*/
105 #define RTIMER_GUARD 0u
106 #elif RTIMER_SECOND >= 200000
107 #define RTIMER_GUARD (RTIMER_SECOND / 100000)
108 #else
109 #define RTIMER_GUARD 2u
110 #endif
111 
112 enum tsch_radio_state_on_cmd {
113  TSCH_RADIO_CMD_ON_START_OF_TIMESLOT,
114  TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT,
115  TSCH_RADIO_CMD_ON_FORCE,
116 };
117 
118 enum tsch_radio_state_off_cmd {
119  TSCH_RADIO_CMD_OFF_END_OF_TIMESLOT,
120  TSCH_RADIO_CMD_OFF_WITHIN_TIMESLOT,
121  TSCH_RADIO_CMD_OFF_FORCE,
122 };
123 
124 /* A ringbuf storing outgoing packets after they were dequeued.
125  * Will be processed layer by tsch_tx_process_pending */
126 struct ringbufindex dequeued_ringbuf;
127 struct tsch_packet *dequeued_array[TSCH_DEQUEUED_ARRAY_SIZE];
128 /* A ringbuf storing incoming packets.
129  * Will be processed layer by tsch_rx_process_pending */
130 struct ringbufindex input_ringbuf;
131 struct input_packet input_array[TSCH_MAX_INCOMING_PACKETS];
132 
133 /* Last time we received Sync-IE (ACK or data packet from a time source) */
134 static struct tsch_asn_t last_sync_asn;
135 clock_time_t last_sync_time; /* Same info, in clock_time_t units */
136 
137 /* A global lock for manipulating data structures safely from outside of interrupt */
138 static volatile int tsch_locked = 0;
139 /* As long as this is set, skip all slot operation */
140 static volatile int tsch_lock_requested = 0;
141 
142 /* Last estimated drift in RTIMER ticks
143  * (Sky: 1 tick = 30.517578125 usec exactly) */
144 static int32_t drift_correction = 0;
145 /* Is drift correction used? (Can be true even if drift_correction == 0) */
146 static uint8_t is_drift_correction_used;
147 
148 /* The neighbor last used as our time source */
150 
151 /* Used from tsch_slot_operation and sub-protothreads */
152 static rtimer_clock_t volatile current_slot_start;
153 
154 /* Are we currently inside a slot? */
155 static volatile int tsch_in_slot_operation = 0;
156 
157 /* If we are inside a slot, this tells the current channel */
158 uint8_t tsch_current_channel;
159 
160 /* Info about the link, packet and neighbor of
161  * the current (or next) slot */
162 struct tsch_link *current_link = NULL;
163 /* A backup link with Rx flag, overlapping with current_link.
164  * If the current link is Tx-only and the Tx queue
165  * is empty while executing the link, fallback to the backup link. */
166 static struct tsch_link *backup_link = NULL;
167 static struct tsch_packet *current_packet = NULL;
168 static struct tsch_neighbor *current_neighbor = NULL;
169 
170 /* Indicates whether an extra link is needed to handle the current burst */
171 static int burst_link_scheduled = 0;
172 /* Counts the length of the current burst */
173 int tsch_current_burst_count = 0;
174 
175 /* Protothread for association */
176 PT_THREAD(tsch_scan(struct pt *pt));
177 /* Protothread for slot operation, called from rtimer interrupt
178  * and scheduled from tsch_schedule_slot_operation */
179 static PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr));
180 static struct pt slot_operation_pt;
181 /* Sub-protothreads of tsch_slot_operation */
182 static PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t));
183 static PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t));
184 
185 /*---------------------------------------------------------------------------*/
186 /* TSCH locking system. TSCH is locked during slot operations */
187 
188 /* Is TSCH locked? */
189 int
191 {
192  return tsch_locked;
193 }
194 
195 /* Lock TSCH (no slot operation) */
196 int
198 {
199  if(!tsch_locked) {
200  rtimer_clock_t busy_wait_time;
201  int busy_wait = 0; /* Flag used for logging purposes */
202  /* Make sure no new slot operation will start */
203  tsch_lock_requested = 1;
204  /* Wait for the end of current slot operation. */
205  if(tsch_in_slot_operation) {
206  busy_wait = 1;
207  busy_wait_time = RTIMER_NOW();
208  while(tsch_in_slot_operation) {
209 #if CONTIKI_TARGET_COOJA
210  simProcessRunValue = 1;
211  cooja_mt_yield();
212 #endif /* CONTIKI_TARGET_COOJA */
213  }
214  busy_wait_time = RTIMER_NOW() - busy_wait_time;
215  }
216  if(!tsch_locked) {
217  /* Take the lock if it is free */
218  tsch_locked = 1;
219  tsch_lock_requested = 0;
220  if(busy_wait) {
221  /* Issue a log whenever we had to busy wait until getting the lock */
222  TSCH_LOG_ADD(tsch_log_message,
223  snprintf(log->message, sizeof(log->message),
224  "!get lock delay %u", (unsigned)busy_wait_time);
225  );
226  }
227  return 1;
228  }
229  }
230  TSCH_LOG_ADD(tsch_log_message,
231  snprintf(log->message, sizeof(log->message),
232  "!failed to lock");
233  );
234  return 0;
235 }
236 
237 /* Release TSCH lock */
238 void
240 {
241  tsch_locked = 0;
242 }
243 
244 /*---------------------------------------------------------------------------*/
245 /* Channel hopping utility functions */
246 
247 /* Return channel from ASN and channel offset */
248 uint8_t
249 tsch_calculate_channel(struct tsch_asn_t *asn, uint8_t channel_offset)
250 {
251  uint16_t index_of_0 = TSCH_ASN_MOD(*asn, tsch_hopping_sequence_length);
252  uint16_t index_of_offset = (index_of_0 + channel_offset) % tsch_hopping_sequence_length.val;
253  return tsch_hopping_sequence[index_of_offset];
254 }
255 
256 /*---------------------------------------------------------------------------*/
257 /* Timing utility functions */
258 
259 /* Checks if the current time has passed a ref time + offset. Assumes
260  * a single overflow and ref time prior to now. */
261 static uint8_t
262 check_timer_miss(rtimer_clock_t ref_time, rtimer_clock_t offset, rtimer_clock_t now)
263 {
264  rtimer_clock_t target = ref_time + offset;
265  int now_has_overflowed = now < ref_time;
266  int target_has_overflowed = target < ref_time;
267 
268  if(now_has_overflowed == target_has_overflowed) {
269  /* Both or none have overflowed, just compare now to the target */
270  return target <= now;
271  } else {
272  /* Either now or target of overflowed.
273  * If it is now, then it has passed the target.
274  * If it is target, then we haven't reached it yet.
275  * */
276  return now_has_overflowed;
277  }
278 }
279 /*---------------------------------------------------------------------------*/
280 /* Schedule a wakeup at a specified offset from a reference time.
281  * Provides basic protection against missed deadlines and timer overflows
282  * A return value of zero signals a missed deadline: no rtimer was scheduled. */
283 static uint8_t
284 tsch_schedule_slot_operation(struct rtimer *tm, rtimer_clock_t ref_time, rtimer_clock_t offset, const char *str)
285 {
286  rtimer_clock_t now = RTIMER_NOW();
287  int r;
288  /* Subtract RTIMER_GUARD before checking for deadline miss
289  * because we can not schedule rtimer less than RTIMER_GUARD in the future */
290  int missed = check_timer_miss(ref_time, offset - RTIMER_GUARD, now);
291 
292  if(missed) {
293  TSCH_LOG_ADD(tsch_log_message,
294  snprintf(log->message, sizeof(log->message),
295  "!dl-miss %s %d %d",
296  str, (int)(now-ref_time), (int)offset);
297  );
298  } else {
299  r = rtimer_set(tm, ref_time + offset, 1, (void (*)(struct rtimer *, void *))tsch_slot_operation, NULL);
300  if(r == RTIMER_OK) {
301  return 1;
302  }
303  }
304 
305  /* block until the time to schedule comes */
306  BUSYWAIT_UNTIL_ABS(0, ref_time, offset);
307  return 0;
308 }
309 /*---------------------------------------------------------------------------*/
310 /* Schedule slot operation conditionally, and YIELD if success only.
311  * Always attempt to schedule RTIMER_GUARD before the target to make sure to wake up
312  * ahead of time and then busy wait to exactly hit the target. */
313 #define TSCH_SCHEDULE_AND_YIELD(pt, tm, ref_time, offset, str) \
314  do { \
315  if(tsch_schedule_slot_operation(tm, ref_time, offset - RTIMER_GUARD, str)) { \
316  PT_YIELD(pt); \
317  BUSYWAIT_UNTIL_ABS(0, ref_time, offset); \
318  } \
319  } while(0);
320 /*---------------------------------------------------------------------------*/
321 /* Get EB, broadcast or unicast packet to be sent, and target neighbor. */
322 static struct tsch_packet *
323 get_packet_and_neighbor_for_link(struct tsch_link *link, struct tsch_neighbor **target_neighbor)
324 {
325  struct tsch_packet *p = NULL;
326  struct tsch_neighbor *n = NULL;
327 
328  /* Is this a Tx link? */
329  if(link->link_options & LINK_OPTION_TX) {
330  /* is it for advertisement of EB? */
331  if(link->link_type == LINK_TYPE_ADVERTISING || link->link_type == LINK_TYPE_ADVERTISING_ONLY) {
332  /* fetch EB packets */
333  n = n_eb;
334  p = tsch_queue_get_packet_for_nbr(n, link);
335  }
336  if(link->link_type != LINK_TYPE_ADVERTISING_ONLY) {
337  /* NORMAL link or no EB to send, pick a data packet */
338  if(p == NULL) {
339  /* Get neighbor queue associated to the link and get packet from it */
340  n = tsch_queue_get_nbr(&link->addr);
341  p = tsch_queue_get_packet_for_nbr(n, link);
342  /* if it is a broadcast slot and there were no broadcast packets, pick any unicast packet */
343  if(p == NULL && n == n_broadcast) {
345  }
346  }
347  }
348  }
349  /* return nbr (by reference) */
350  if(target_neighbor != NULL) {
351  *target_neighbor = n;
352  }
353 
354  return p;
355 }
356 /*---------------------------------------------------------------------------*/
357 /**
358  * This function turns on the radio. Its semantics is dependent on
359  * the value of TSCH_RADIO_ON_DURING_TIMESLOT constant:
360  * - if enabled, the radio is turned on at the start of the slot
361  * - if disabled, the radio is turned on within the slot,
362  * directly before the packet Rx guard time and ACK Rx guard time.
363  */
364 static void
365 tsch_radio_on(enum tsch_radio_state_on_cmd command)
366 {
367  int do_it = 0;
368  switch(command) {
369  case TSCH_RADIO_CMD_ON_START_OF_TIMESLOT:
370  if(TSCH_RADIO_ON_DURING_TIMESLOT) {
371  do_it = 1;
372  }
373  break;
374  case TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT:
375  if(!TSCH_RADIO_ON_DURING_TIMESLOT) {
376  do_it = 1;
377  }
378  break;
379  case TSCH_RADIO_CMD_ON_FORCE:
380  do_it = 1;
381  break;
382  }
383  if(do_it) {
384  NETSTACK_RADIO.on();
385  }
386 }
387 /*---------------------------------------------------------------------------*/
388 /**
389  * This function turns off the radio. In the same way as for tsch_radio_on(),
390  * it depends on the value of TSCH_RADIO_ON_DURING_TIMESLOT constant:
391  * - if enabled, the radio is turned off at the end of the slot
392  * - if disabled, the radio is turned off within the slot,
393  * directly after Tx'ing or Rx'ing a packet or Tx'ing an ACK.
394  */
395 static void
396 tsch_radio_off(enum tsch_radio_state_off_cmd command)
397 {
398  int do_it = 0;
399  switch(command) {
400  case TSCH_RADIO_CMD_OFF_END_OF_TIMESLOT:
401  if(TSCH_RADIO_ON_DURING_TIMESLOT) {
402  do_it = 1;
403  }
404  break;
405  case TSCH_RADIO_CMD_OFF_WITHIN_TIMESLOT:
406  if(!TSCH_RADIO_ON_DURING_TIMESLOT) {
407  do_it = 1;
408  }
409  break;
410  case TSCH_RADIO_CMD_OFF_FORCE:
411  do_it = 1;
412  break;
413  }
414  if(do_it) {
415  NETSTACK_RADIO.off();
416  }
417 }
418 /*---------------------------------------------------------------------------*/
419 static
420 PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t))
421 {
422  /**
423  * TX slot:
424  * 1. Copy packet to radio buffer
425  * 2. Perform CCA if enabled
426  * 3. Sleep until it is time to transmit
427  * 4. Wait for ACK if it is a unicast packet
428  * 5. Extract drift if we received an E-ACK from a time source neighbor
429  * 6. Update CSMA parameters according to TX status
430  * 7. Schedule mac_call_sent_callback
431  **/
432 
433  /* tx status */
434  static uint8_t mac_tx_status;
435  /* is the packet in its neighbor's queue? */
436  uint8_t in_queue;
437  static int dequeued_index;
438  static int packet_ready = 1;
439 
440  PT_BEGIN(pt);
441 
442  TSCH_DEBUG_TX_EVENT();
443 
444  /* First check if we have space to store a newly dequeued packet (in case of
445  * successful Tx or Drop) */
446  dequeued_index = ringbufindex_peek_put(&dequeued_ringbuf);
447  if(dequeued_index != -1) {
448  if(current_packet == NULL || current_packet->qb == NULL) {
449  mac_tx_status = MAC_TX_ERR_FATAL;
450  } else {
451  /* packet payload */
452  static void *packet;
453 #if LLSEC802154_ENABLED
454  /* encrypted payload */
455  static uint8_t encrypted_packet[TSCH_PACKET_MAX_LEN];
456 #endif /* LLSEC802154_ENABLED */
457  /* packet payload length */
458  static uint8_t packet_len;
459  /* packet seqno */
460  static uint8_t seqno;
461  /* is this a broadcast packet? (wait for ack?) */
462  static uint8_t is_broadcast;
463  static rtimer_clock_t tx_start_time;
464  /* Did we set the frame pending bit to request an extra burst link? */
465  static int burst_link_requested;
466 
467 #if CCA_ENABLED
468  static uint8_t cca_status;
469 #endif
470 
471  /* get payload */
472  packet = queuebuf_dataptr(current_packet->qb);
473  packet_len = queuebuf_datalen(current_packet->qb);
474  /* is this a broadcast packet? (wait for ack?) */
475  is_broadcast = current_neighbor->is_broadcast;
476  /* Unicast. More packets in queue for the neighbor? */
477  burst_link_requested = 0;
478  if(!is_broadcast
479  && tsch_current_burst_count + 1 < TSCH_BURST_MAX_LEN
480  && tsch_queue_packet_count(&current_neighbor->addr) > 1) {
481  burst_link_requested = 1;
482  tsch_packet_set_frame_pending(packet, packet_len);
483  }
484  /* read seqno from payload */
485  seqno = ((uint8_t *)(packet))[2];
486  /* if this is an EB, then update its Sync-IE */
487  if(current_neighbor == n_eb) {
488  packet_ready = tsch_packet_update_eb(packet, packet_len, current_packet->tsch_sync_ie_offset);
489  } else {
490  packet_ready = 1;
491  }
492 
493 #if LLSEC802154_ENABLED
494  if(tsch_is_pan_secured) {
495  /* If we are going to encrypt, we need to generate the output in a separate buffer and keep
496  * the original untouched. This is to allow for future retransmissions. */
497  int with_encryption = queuebuf_attr(current_packet->qb, PACKETBUF_ATTR_SECURITY_LEVEL) & 0x4;
498  packet_len += tsch_security_secure_frame(packet, with_encryption ? encrypted_packet : packet, current_packet->header_len,
499  packet_len - current_packet->header_len, &tsch_current_asn);
500  if(with_encryption) {
501  packet = encrypted_packet;
502  }
503  }
504 #endif /* LLSEC802154_ENABLED */
505 
506  /* prepare packet to send: copy to radio buffer */
507  if(packet_ready && NETSTACK_RADIO.prepare(packet, packet_len) == 0) { /* 0 means success */
508  static rtimer_clock_t tx_duration;
509 
510 #if CCA_ENABLED
511  cca_status = 1;
512  /* delay before CCA */
513  TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, TS_CCA_OFFSET, "cca");
514  TSCH_DEBUG_TX_EVENT();
515  tsch_radio_on(TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT);
516  /* CCA */
517  BUSYWAIT_UNTIL_ABS(!(cca_status |= NETSTACK_RADIO.channel_clear()),
518  current_slot_start, TS_CCA_OFFSET + TS_CCA);
519  TSCH_DEBUG_TX_EVENT();
520  /* there is not enough time to turn radio off */
521  /* NETSTACK_RADIO.off(); */
522  if(cca_status == 0) {
523  mac_tx_status = MAC_TX_COLLISION;
524  } else
525 #endif /* CCA_ENABLED */
526  {
527  /* delay before TX */
528  TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, tsch_timing[tsch_ts_tx_offset] - RADIO_DELAY_BEFORE_TX, "TxBeforeTx");
529  TSCH_DEBUG_TX_EVENT();
530  /* send packet already in radio tx buffer */
531  mac_tx_status = NETSTACK_RADIO.transmit(packet_len);
532  tx_count++;
533  /* Save tx timestamp */
534  tx_start_time = current_slot_start + tsch_timing[tsch_ts_tx_offset];
535  /* calculate TX duration based on sent packet len */
536  tx_duration = TSCH_PACKET_DURATION(packet_len);
537  /* limit tx_time to its max value */
538  tx_duration = MIN(tx_duration, tsch_timing[tsch_ts_max_tx]);
539  /* turn tadio off -- will turn on again to wait for ACK if needed */
540  tsch_radio_off(TSCH_RADIO_CMD_OFF_WITHIN_TIMESLOT);
541 
542  if(mac_tx_status == RADIO_TX_OK) {
543  if(!is_broadcast) {
544  uint8_t ackbuf[TSCH_PACKET_MAX_LEN];
545  int ack_len;
546  rtimer_clock_t ack_start_time;
547  int is_time_source;
548  struct ieee802154_ies ack_ies;
549  uint8_t ack_hdrlen;
550  frame802154_t frame;
551 
552 #if TSCH_HW_FRAME_FILTERING
553  radio_value_t radio_rx_mode;
554  /* Entering promiscuous mode so that the radio accepts the enhanced ACK */
555  NETSTACK_RADIO.get_value(RADIO_PARAM_RX_MODE, &radio_rx_mode);
556  NETSTACK_RADIO.set_value(RADIO_PARAM_RX_MODE, radio_rx_mode & (~RADIO_RX_MODE_ADDRESS_FILTER));
557 #endif /* TSCH_HW_FRAME_FILTERING */
558  /* Unicast: wait for ack after tx: sleep until ack time */
559  TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start,
560  tsch_timing[tsch_ts_tx_offset] + tx_duration + tsch_timing[tsch_ts_rx_ack_delay] - RADIO_DELAY_BEFORE_RX, "TxBeforeAck");
561  TSCH_DEBUG_TX_EVENT();
562  tsch_radio_on(TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT);
563  /* Wait for ACK to come */
564  BUSYWAIT_UNTIL_ABS(NETSTACK_RADIO.receiving_packet(),
565  tx_start_time, tx_duration + tsch_timing[tsch_ts_rx_ack_delay] + tsch_timing[tsch_ts_ack_wait] + RADIO_DELAY_BEFORE_DETECT);
566  TSCH_DEBUG_TX_EVENT();
567 
568  ack_start_time = RTIMER_NOW() - RADIO_DELAY_BEFORE_DETECT;
569 
570  /* Wait for ACK to finish */
571  BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(),
572  ack_start_time, tsch_timing[tsch_ts_max_ack]);
573  TSCH_DEBUG_TX_EVENT();
574  tsch_radio_off(TSCH_RADIO_CMD_OFF_WITHIN_TIMESLOT);
575 
576 #if TSCH_HW_FRAME_FILTERING
577  /* Leaving promiscuous mode */
578  NETSTACK_RADIO.get_value(RADIO_PARAM_RX_MODE, &radio_rx_mode);
579  NETSTACK_RADIO.set_value(RADIO_PARAM_RX_MODE, radio_rx_mode | RADIO_RX_MODE_ADDRESS_FILTER);
580 #endif /* TSCH_HW_FRAME_FILTERING */
581 
582  /* Read ack frame */
583  ack_len = NETSTACK_RADIO.read((void *)ackbuf, sizeof(ackbuf));
584 
585  is_time_source = 0;
586  /* The radio driver should return 0 if no valid packets are in the rx buffer */
587  if(ack_len > 0) {
588  is_time_source = current_neighbor != NULL && current_neighbor->is_time_source;
589  if(tsch_packet_parse_eack(ackbuf, ack_len, seqno,
590  &frame, &ack_ies, &ack_hdrlen) == 0) {
591  ack_len = 0;
592  }
593 
594 #if LLSEC802154_ENABLED
595  if(ack_len != 0) {
596  if(!tsch_security_parse_frame(ackbuf, ack_hdrlen, ack_len - ack_hdrlen - tsch_security_mic_len(&frame),
597  &frame, &current_neighbor->addr, &tsch_current_asn)) {
598  TSCH_LOG_ADD(tsch_log_message,
599  snprintf(log->message, sizeof(log->message),
600  "!failed to authenticate ACK"));
601  ack_len = 0;
602  }
603  } else {
604  TSCH_LOG_ADD(tsch_log_message,
605  snprintf(log->message, sizeof(log->message),
606  "!failed to parse ACK"));
607  }
608 #endif /* LLSEC802154_ENABLED */
609  }
610 
611  if(ack_len != 0) {
612  if(is_time_source) {
613  int32_t eack_time_correction = US_TO_RTIMERTICKS(ack_ies.ie_time_correction);
614  int32_t since_last_timesync = TSCH_ASN_DIFF(tsch_current_asn, last_sync_asn);
615  if(eack_time_correction > SYNC_IE_BOUND) {
616  drift_correction = SYNC_IE_BOUND;
617  } else if(eack_time_correction < -SYNC_IE_BOUND) {
618  drift_correction = -SYNC_IE_BOUND;
619  } else {
620  drift_correction = eack_time_correction;
621  }
622  if(drift_correction != eack_time_correction) {
623  TSCH_LOG_ADD(tsch_log_message,
624  snprintf(log->message, sizeof(log->message),
625  "!truncated dr %d %d", (int)eack_time_correction, (int)drift_correction);
626  );
627  }
628  is_drift_correction_used = 1;
629  tsch_timesync_update(current_neighbor, since_last_timesync, drift_correction);
630  /* Keep track of sync time */
631  last_sync_asn = tsch_current_asn;
632  last_sync_time = clock_time();
634  }
635  mac_tx_status = MAC_TX_OK;
636 
637  /* We requested an extra slot and got an ack. This means
638  the extra slot will be scheduled at the received */
639  if(burst_link_requested) {
640  burst_link_scheduled = 1;
641  }
642  } else {
643  mac_tx_status = MAC_TX_NOACK;
644  }
645  } else {
646  mac_tx_status = MAC_TX_OK;
647  }
648  } else {
649  mac_tx_status = MAC_TX_ERR;
650  }
651  }
652  }
653  }
654 
655  tsch_radio_off(TSCH_RADIO_CMD_OFF_END_OF_TIMESLOT);
656 
657  current_packet->transmissions++;
658  current_packet->ret = mac_tx_status;
659 
660  /* Post TX: Update neighbor queue state */
661  in_queue = tsch_queue_packet_sent(current_neighbor, current_packet, current_link, mac_tx_status);
662 
663  /* The packet was dequeued, add it to dequeued_ringbuf for later processing */
664  if(in_queue == 0) {
665  dequeued_array[dequeued_index] = current_packet;
666  ringbufindex_put(&dequeued_ringbuf);
667  }
668 
669  /* Log every tx attempt */
670  TSCH_LOG_ADD(tsch_log_tx,
671  log->tx.mac_tx_status = mac_tx_status;
672  log->tx.num_tx = current_packet->transmissions;
673  log->tx.datalen = queuebuf_datalen(current_packet->qb);
674  log->tx.drift = drift_correction;
675  log->tx.drift_used = is_drift_correction_used;
676  log->tx.is_data = ((((uint8_t *)(queuebuf_dataptr(current_packet->qb)))[0]) & 7) == FRAME802154_DATAFRAME;
677 #if LLSEC802154_ENABLED
678  log->tx.sec_level = queuebuf_attr(current_packet->qb, PACKETBUF_ATTR_SECURITY_LEVEL);
679 #else /* LLSEC802154_ENABLED */
680  log->tx.sec_level = 0;
681 #endif /* LLSEC802154_ENABLED */
682  linkaddr_copy(&log->tx.dest, queuebuf_addr(current_packet->qb, PACKETBUF_ADDR_RECEIVER));
683  log->tx.seqno = queuebuf_attr(current_packet->qb, PACKETBUF_ATTR_MAC_SEQNO);
684  );
685 
686  /* Poll process for later processing of packet sent events and logs */
687  process_poll(&tsch_pending_events_process);
688  }
689 
690  TSCH_DEBUG_TX_EVENT();
691 
692  PT_END(pt);
693 }
694 /*---------------------------------------------------------------------------*/
695 static
696 PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t))
697 {
698  /**
699  * RX slot:
700  * 1. Check if it is used for TIME_KEEPING
701  * 2. Sleep and wake up just before expected RX time (with a guard time: TS_LONG_GT)
702  * 3. Check for radio activity for the guard time: TS_LONG_GT
703  * 4. Prepare and send ACK if needed
704  * 5. Drift calculated in the ACK callback registered with the radio driver. Use it if receiving from a time source neighbor.
705  **/
706 
707  struct tsch_neighbor *n;
708  static linkaddr_t source_address;
709  static linkaddr_t destination_address;
710  static int16_t input_index;
711  static int input_queue_drop = 0;
712 
713  PT_BEGIN(pt);
714 
715  TSCH_DEBUG_RX_EVENT();
716 
717  input_index = ringbufindex_peek_put(&input_ringbuf);
718  if(input_index == -1) {
719  input_queue_drop++;
720  } else {
721  static struct input_packet *current_input;
722  /* Estimated drift based on RX time */
723  static int32_t estimated_drift;
724  /* Rx timestamps */
725  static rtimer_clock_t rx_start_time;
726  static rtimer_clock_t expected_rx_time;
727  static rtimer_clock_t packet_duration;
728  uint8_t packet_seen;
729 
730  expected_rx_time = current_slot_start + tsch_timing[tsch_ts_tx_offset];
731  /* Default start time: expected Rx time */
732  rx_start_time = expected_rx_time;
733 
734  current_input = &input_array[input_index];
735 
736  /* Wait before starting to listen */
737  TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, tsch_timing[tsch_ts_rx_offset] - RADIO_DELAY_BEFORE_RX, "RxBeforeListen");
738  TSCH_DEBUG_RX_EVENT();
739 
740  /* Start radio for at least guard time */
741  tsch_radio_on(TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT);
742  packet_seen = NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet();
743  if(!packet_seen) {
744  /* Check if receiving within guard time */
745  BUSYWAIT_UNTIL_ABS((packet_seen = NETSTACK_RADIO.receiving_packet()),
746  current_slot_start, tsch_timing[tsch_ts_rx_offset] + tsch_timing[tsch_ts_rx_wait] + RADIO_DELAY_BEFORE_DETECT);
747  }
748  if(!packet_seen) {
749  /* no packets on air */
750  tsch_radio_off(TSCH_RADIO_CMD_OFF_FORCE);
751  } else {
752  TSCH_DEBUG_RX_EVENT();
753  /* Save packet timestamp */
754  rx_start_time = RTIMER_NOW() - RADIO_DELAY_BEFORE_DETECT;
755 
756  /* Wait until packet is received, turn radio off */
757  BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(),
758  current_slot_start, tsch_timing[tsch_ts_rx_offset] + tsch_timing[tsch_ts_rx_wait] + tsch_timing[tsch_ts_max_tx]);
759  TSCH_DEBUG_RX_EVENT();
760  tsch_radio_off(TSCH_RADIO_CMD_OFF_WITHIN_TIMESLOT);
761 
762  if(NETSTACK_RADIO.pending_packet()) {
763  static int frame_valid;
764  static int header_len;
765  static frame802154_t frame;
766  radio_value_t radio_last_rssi;
767 
768  /* Read packet */
769  current_input->len = NETSTACK_RADIO.read((void *)current_input->payload, TSCH_PACKET_MAX_LEN);
770  NETSTACK_RADIO.get_value(RADIO_PARAM_LAST_RSSI, &radio_last_rssi);
771  current_input->rx_asn = tsch_current_asn;
772  current_input->rssi = (signed)radio_last_rssi;
773  current_input->channel = tsch_current_channel;
774  header_len = frame802154_parse((uint8_t *)current_input->payload, current_input->len, &frame);
775  frame_valid = header_len > 0 &&
776  frame802154_check_dest_panid(&frame) &&
777  frame802154_extract_linkaddr(&frame, &source_address, &destination_address);
778 
779 #if TSCH_RESYNC_WITH_SFD_TIMESTAMPS
780  /* At the end of the reception, get an more accurate estimate of SFD arrival time */
781  NETSTACK_RADIO.get_object(RADIO_PARAM_LAST_PACKET_TIMESTAMP, &rx_start_time, sizeof(rtimer_clock_t));
782 #endif
783 
784  packet_duration = TSCH_PACKET_DURATION(current_input->len);
785 
786  if(!frame_valid) {
787  TSCH_LOG_ADD(tsch_log_message,
788  snprintf(log->message, sizeof(log->message),
789  "!failed to parse frame %u %u", header_len, current_input->len));
790  }
791 
792  if(frame_valid) {
793  if(frame.fcf.frame_type != FRAME802154_DATAFRAME
794  && frame.fcf.frame_type != FRAME802154_BEACONFRAME) {
795  TSCH_LOG_ADD(tsch_log_message,
796  snprintf(log->message, sizeof(log->message),
797  "!discarding frame with type %u, len %u", frame.fcf.frame_type, current_input->len));
798  frame_valid = 0;
799  }
800  }
801 
802 #if LLSEC802154_ENABLED
803  /* Decrypt and verify incoming frame */
804  if(frame_valid) {
806  current_input->payload, header_len, current_input->len - header_len - tsch_security_mic_len(&frame),
807  &frame, &source_address, &tsch_current_asn)) {
808  current_input->len -= tsch_security_mic_len(&frame);
809  } else {
810  TSCH_LOG_ADD(tsch_log_message,
811  snprintf(log->message, sizeof(log->message),
812  "!failed to authenticate frame %u", current_input->len));
813  frame_valid = 0;
814  }
815  }
816 #endif /* LLSEC802154_ENABLED */
817 
818  if(frame_valid) {
819  if(linkaddr_cmp(&destination_address, &linkaddr_node_addr)
820  || linkaddr_cmp(&destination_address, &linkaddr_null)) {
821  int do_nack = 0;
822  rx_count++;
823  estimated_drift = RTIMER_CLOCK_DIFF(expected_rx_time, rx_start_time);
824 
825 #if TSCH_TIMESYNC_REMOVE_JITTER
826  /* remove jitter due to measurement errors */
827  if(ABS(estimated_drift) <= TSCH_TIMESYNC_MEASUREMENT_ERROR) {
828  estimated_drift = 0;
829  } else if(estimated_drift > 0) {
830  estimated_drift -= TSCH_TIMESYNC_MEASUREMENT_ERROR;
831  } else {
832  estimated_drift += TSCH_TIMESYNC_MEASUREMENT_ERROR;
833  }
834 #endif
835 
836 #ifdef TSCH_CALLBACK_DO_NACK
837  if(frame.fcf.ack_required) {
838  do_nack = TSCH_CALLBACK_DO_NACK(current_link,
839  &source_address, &destination_address);
840  }
841 #endif
842 
843  if(frame.fcf.ack_required) {
844  static uint8_t ack_buf[TSCH_PACKET_MAX_LEN];
845  static int ack_len;
846 
847  /* Build ACK frame */
848  ack_len = tsch_packet_create_eack(ack_buf, sizeof(ack_buf),
849  &source_address, frame.seq, (int16_t)RTIMERTICKS_TO_US(estimated_drift), do_nack);
850 
851  if(ack_len > 0) {
852 #if LLSEC802154_ENABLED
853  if(tsch_is_pan_secured) {
854  /* Secure ACK frame. There is only header and header IEs, therefore data len == 0. */
855  ack_len += tsch_security_secure_frame(ack_buf, ack_buf, ack_len, 0, &tsch_current_asn);
856  }
857 #endif /* LLSEC802154_ENABLED */
858 
859  /* Copy to radio buffer */
860  NETSTACK_RADIO.prepare((const void *)ack_buf, ack_len);
861 
862  /* Wait for time to ACK and transmit ACK */
863  TSCH_SCHEDULE_AND_YIELD(pt, t, rx_start_time,
864  packet_duration + tsch_timing[tsch_ts_tx_ack_delay] - RADIO_DELAY_BEFORE_TX, "RxBeforeAck");
865  TSCH_DEBUG_RX_EVENT();
866  NETSTACK_RADIO.transmit(ack_len);
867  tsch_radio_off(TSCH_RADIO_CMD_OFF_WITHIN_TIMESLOT);
868 
869  /* Schedule a burst link iff the frame pending bit was set */
870  burst_link_scheduled = tsch_packet_get_frame_pending(current_input->payload, current_input->len);
871  }
872  }
873 
874  /* If the sender is a time source, proceed to clock drift compensation */
875  n = tsch_queue_get_nbr(&source_address);
876  if(n != NULL && n->is_time_source) {
877  int32_t since_last_timesync = TSCH_ASN_DIFF(tsch_current_asn, last_sync_asn);
878  /* Keep track of last sync time */
879  last_sync_asn = tsch_current_asn;
880  last_sync_time = clock_time();
881  /* Save estimated drift */
882  drift_correction = -estimated_drift;
883  is_drift_correction_used = 1;
884  sync_count++;
885  tsch_timesync_update(n, since_last_timesync, -estimated_drift);
887  }
888 
889  /* Add current input to ringbuf */
890  ringbufindex_put(&input_ringbuf);
891 
892  /* Log every reception */
893  TSCH_LOG_ADD(tsch_log_rx,
894  linkaddr_copy(&log->rx.src, (linkaddr_t *)&frame.src_addr);
895  log->rx.is_unicast = frame.fcf.ack_required;
896  log->rx.datalen = current_input->len;
897  log->rx.drift = drift_correction;
898  log->rx.drift_used = is_drift_correction_used;
899  log->rx.is_data = frame.fcf.frame_type == FRAME802154_DATAFRAME;
900  log->rx.sec_level = frame.aux_hdr.security_control.security_level;
901  log->rx.estimated_drift = estimated_drift;
902  log->rx.seqno = frame.seq;
903  );
904  }
905 
906  /* Poll process for processing of pending input and logs */
907  process_poll(&tsch_pending_events_process);
908  }
909  }
910 
911  tsch_radio_off(TSCH_RADIO_CMD_OFF_END_OF_TIMESLOT);
912  }
913 
914  if(input_queue_drop != 0) {
915  TSCH_LOG_ADD(tsch_log_message,
916  snprintf(log->message, sizeof(log->message),
917  "!queue full skipped %u", input_queue_drop);
918  );
919  input_queue_drop = 0;
920  }
921  }
922 
923  TSCH_DEBUG_RX_EVENT();
924 
925  PT_END(pt);
926 }
927 /*---------------------------------------------------------------------------*/
928 /* Protothread for slot operation, called from rtimer interrupt
929  * and scheduled from tsch_schedule_slot_operation */
930 static
931 PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr))
932 {
933  TSCH_DEBUG_INTERRUPT();
934  PT_BEGIN(&slot_operation_pt);
935 
936  /* Loop over all active slots */
937  while(tsch_is_associated) {
938 
939  if(current_link == NULL || tsch_lock_requested) { /* Skip slot operation if there is no link
940  or if there is a pending request for getting the lock */
941  /* Issue a log whenever skipping a slot */
942  TSCH_LOG_ADD(tsch_log_message,
943  snprintf(log->message, sizeof(log->message),
944  "!skipped slot %u %u %u",
945  tsch_locked,
946  tsch_lock_requested,
947  current_link == NULL);
948  );
949 
950  } else {
951  int is_active_slot;
952  TSCH_DEBUG_SLOT_START();
953  tsch_in_slot_operation = 1;
954  /* Reset drift correction */
955  drift_correction = 0;
956  is_drift_correction_used = 0;
957  /* Get a packet ready to be sent */
958  current_packet = get_packet_and_neighbor_for_link(current_link, &current_neighbor);
959  /* There is no packet to send, and this link does not have Rx flag. Instead of doing
960  * nothing, switch to the backup link (has Rx flag) if any. */
961  if(current_packet == NULL && !(current_link->link_options & LINK_OPTION_RX) && backup_link != NULL) {
962  current_link = backup_link;
963  current_packet = get_packet_and_neighbor_for_link(current_link, &current_neighbor);
964  }
965  is_active_slot = current_packet != NULL || (current_link->link_options & LINK_OPTION_RX);
966  if(is_active_slot) {
967  /* If we are in a burst, we stick to current channel instead of
968  * doing channel hopping, as per IEEE 802.15.4-2015 */
969  if(burst_link_scheduled) {
970  /* Reset burst_link_scheduled flag. Will be set again if burst continue. */
971  burst_link_scheduled = 0;
972  } else {
973  /* Hop channel */
974  tsch_current_channel = tsch_calculate_channel(&tsch_current_asn, current_link->channel_offset);
975  }
976  NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, tsch_current_channel);
977  /* Turn the radio on already here if configured so; necessary for radios with slow startup */
978  tsch_radio_on(TSCH_RADIO_CMD_ON_START_OF_TIMESLOT);
979  /* Decide whether it is a TX/RX/IDLE or OFF slot */
980  /* Actual slot operation */
981  if(current_packet != NULL) {
982  /* We have something to transmit, do the following:
983  * 1. send
984  * 2. update_backoff_state(current_neighbor)
985  * 3. post tx callback
986  **/
987  static struct pt slot_tx_pt;
988  PT_SPAWN(&slot_operation_pt, &slot_tx_pt, tsch_tx_slot(&slot_tx_pt, t));
989  } else {
990  /* Listen */
991  static struct pt slot_rx_pt;
992  PT_SPAWN(&slot_operation_pt, &slot_rx_pt, tsch_rx_slot(&slot_rx_pt, t));
993  }
994  } else {
995  /* Make sure to end the burst in cast, for some reason, we were
996  * in a burst but now without any more packet to send. */
997  burst_link_scheduled = 0;
998  }
999  TSCH_DEBUG_SLOT_END();
1000  }
1001 
1002  /* End of slot operation, schedule next slot or resynchronize */
1003 
1004  /* Do we need to resynchronize? i.e., wait for EB again */
1005  if(!tsch_is_coordinator && (TSCH_ASN_DIFF(tsch_current_asn, last_sync_asn) >
1006  (100 * TSCH_CLOCK_TO_SLOTS(TSCH_DESYNC_THRESHOLD / 100, tsch_timing[tsch_ts_timeslot_length])))) {
1007  TSCH_LOG_ADD(tsch_log_message,
1008  snprintf(log->message, sizeof(log->message),
1009  "! leaving the network, last sync %u",
1010  (unsigned)TSCH_ASN_DIFF(tsch_current_asn, last_sync_asn));
1011  );
1012  last_timesource_neighbor = NULL;
1014  } else {
1015  /* backup of drift correction for printing debug messages */
1016  /* int32_t drift_correction_backup = drift_correction; */
1017  uint16_t timeslot_diff = 0;
1018  rtimer_clock_t prev_slot_start;
1019  /* Time to next wake up */
1020  rtimer_clock_t time_to_next_active_slot;
1021  /* Schedule next wakeup skipping slots if missed deadline */
1022  do {
1023  if(current_link != NULL
1024  && current_link->link_options & LINK_OPTION_TX
1025  && current_link->link_options & LINK_OPTION_SHARED) {
1026  /* Decrement the backoff window for all neighbors able to transmit over
1027  * this Tx, Shared link. */
1028  tsch_queue_update_all_backoff_windows(&current_link->addr);
1029  }
1030 
1031  /* A burst link was scheduled. Replay the current link at the
1032  next time offset */
1033  if(burst_link_scheduled) {
1034  timeslot_diff = 1;
1035  backup_link = NULL;
1036  /* Keep track of the number of repetitions */
1037  tsch_current_burst_count++;
1038  } else {
1039  /* Get next active link */
1040  current_link = tsch_schedule_get_next_active_link(&tsch_current_asn, &timeslot_diff, &backup_link);
1041  if(current_link == NULL) {
1042  /* There is no next link. Fall back to default
1043  * behavior: wake up at the next slot. */
1044  timeslot_diff = 1;
1045  } else {
1046  /* Reset burst index now that the link was scheduled from
1047  normal schedule (as opposed to from ongoing burst) */
1048  tsch_current_burst_count = 0;
1049  }
1050  }
1051 
1052  /* Update ASN */
1053  TSCH_ASN_INC(tsch_current_asn, timeslot_diff);
1054  /* Time to next wake up */
1055  time_to_next_active_slot = timeslot_diff * tsch_timing[tsch_ts_timeslot_length] + drift_correction;
1056  time_to_next_active_slot += tsch_timesync_adaptive_compensate(time_to_next_active_slot);
1057  drift_correction = 0;
1058  is_drift_correction_used = 0;
1059  /* Update current slot start */
1060  prev_slot_start = current_slot_start;
1061  current_slot_start += time_to_next_active_slot;
1062  } while(!tsch_schedule_slot_operation(t, prev_slot_start, time_to_next_active_slot, "main"));
1063  }
1064 
1065  tsch_in_slot_operation = 0;
1066  PT_YIELD(&slot_operation_pt);
1067  }
1068 
1069  PT_END(&slot_operation_pt);
1070 }
1071 /*---------------------------------------------------------------------------*/
1072 /* Set global time before starting slot operation,
1073  * with a rtimer time and an ASN */
1074 void
1076 {
1077  static struct rtimer slot_operation_timer;
1078  rtimer_clock_t time_to_next_active_slot;
1079  rtimer_clock_t prev_slot_start;
1080  TSCH_DEBUG_INIT();
1081  do {
1082  uint16_t timeslot_diff;
1083  /* Get next active link */
1084  current_link = tsch_schedule_get_next_active_link(&tsch_current_asn, &timeslot_diff, &backup_link);
1085  if(current_link == NULL) {
1086  /* There is no next link. Fall back to default
1087  * behavior: wake up at the next slot. */
1088  timeslot_diff = 1;
1089  }
1090  /* Update ASN */
1091  TSCH_ASN_INC(tsch_current_asn, timeslot_diff);
1092  /* Time to next wake up */
1093  time_to_next_active_slot = timeslot_diff * tsch_timing[tsch_ts_timeslot_length];
1094  /* Update current slot start */
1095  prev_slot_start = current_slot_start;
1096  current_slot_start += time_to_next_active_slot;
1097  } while(!tsch_schedule_slot_operation(&slot_operation_timer, prev_slot_start, time_to_next_active_slot, "assoc"));
1098 }
1099 /*---------------------------------------------------------------------------*/
1100 /* Start actual slot operation */
1101 void
1102 tsch_slot_operation_sync(rtimer_clock_t next_slot_start,
1103  struct tsch_asn_t *next_slot_asn)
1104 {
1105  current_slot_start = next_slot_start;
1106  tsch_current_asn = *next_slot_asn;
1107  last_sync_asn = tsch_current_asn;
1108  last_sync_time = clock_time();
1109  current_link = NULL;
1110 }
1111 /*---------------------------------------------------------------------------*/
1112 /** @} */
TSCH packet information.
Definition: tsch-types.h:97
#define TSCH_LOG_ADD(log_type, init_code)
Use this macro to add a log to the queue (will be printed out later, after leaving interrupt context)...
Definition: tsch-log.h:140
frame802154_scf_t security_control
Security control bitfield.
Definition: frame802154.h:188
struct tsch_neighbor * tsch_queue_get_nbr(const linkaddr_t *addr)
Get a TSCH neighbor.
Definition: tsch-queue.c:108
static void tsch_radio_off(enum tsch_radio_state_off_cmd command)
This function turns off the radio.
int rtimer_set(struct rtimer *rtimer, rtimer_clock_t time, rtimer_clock_t duration, rtimer_callback_t func, void *ptr)
Post a real-time task.
Definition: rtimer.c:67
The MAC layer did not get an acknowledgement for the packet.
Definition: mac.h:88
frame802154_fcf_t fcf
Frame control field.
Definition: frame802154.h:204
Representation of a real-time task.
Definition: rtimer.h:109
struct tsch_neighbor * last_timesource_neighbor
The neighbor last used as our time source.
int tsch_get_lock(void)
Takes the TSCH lock.
Header file for the radio API
uint8_t security_level
3 bit.
Definition: frame802154.h:168
void tsch_release_lock(void)
Releases the TSCH lock.
int frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
Parses an input frame.
Definition: frame802154.c:500
TSCH neighbor information.
Definition: tsch-types.h:109
void tsch_queue_update_all_backoff_windows(const linkaddr_t *dest_addr)
Decrement backoff window for the queue(s) able to Tx to a given address.
Definition: tsch-queue.c:501
unsigned int tsch_security_parse_frame(const uint8_t *hdr, int hdrlen, int datalen, const frame802154_t *frame, const linkaddr_t *sender, struct tsch_asn_t *asn)
Parse and check a frame protected with encryption and/or MIC.
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
Definition: pt.h:114
void tsch_timesync_update(struct tsch_neighbor *n, uint16_t time_delta_asn, int32_t drift_correction)
Updates timesync information for a given neighbor.
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
uint8_t src_addr[8]
Source address.
Definition: frame802154.h:203
void tsch_schedule_keepalive(void)
Schedule a keep-alive transmission within [timeout*0.9, timeout[.
Definition: tsch.c:314
A MAC framer for IEEE 802.15.4
const linkaddr_t linkaddr_null
The null link-layer address.
#define PT_SPAWN(pt, child, thread)
Spawn a child protothread and wait until it exits.
Definition: pt.h:205
The MAC layer transmission was OK.
Definition: mac.h:84
int tsch_packet_update_eb(uint8_t *buf, int buf_size, uint8_t tsch_sync_ie_offset)
Update ASN in EB packet.
Definition: tsch-packet.c:391
linkaddr_t linkaddr_node_addr
The link-layer address of the node.
Definition: linkaddr.c:48
uint8_t tsch_calculate_channel(struct tsch_asn_t *asn, uint8_t channel_offset)
Returns a 802.15.4 channel from an ASN and channel offset.
#define RTIMER_NOW()
Get the current clock time.
Definition: rtimer.h:158
int32_t tsch_timesync_adaptive_compensate(rtimer_clock_t delta_ticks)
Computes time compensation for a given point in the future.
unsigned int tsch_security_mic_len(const frame802154_t *frame)
Return MIC length.
#define PT_END(pt)
Declare the end of a protothread.
Definition: pt.h:126
Header file for the Packet queue buffer management
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
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)
#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
#define PT_YIELD(pt)
Yield from the current protothread.
Definition: pt.h:289
int tsch_packet_parse_eack(const uint8_t *buf, int buf_size, uint8_t seqno, frame802154_t *frame, struct ieee802154_ies *ies, uint8_t *hdr_len)
Parse enhanced ACK packet.
Definition: tsch-packet.c:162
Main API declarations for TSCH.
clock_time_t clock_time(void)
Get the current clock time.
Definition: clock.c:118
The MAC layer transmission could not be performed because of a fatal error.
Definition: mac.h:98
struct tsch_packet * tsch_queue_get_packet_for_nbr(const struct tsch_neighbor *n, struct tsch_link *link)
Returns the first packet that can be sent from a queue on a given link.
Definition: tsch-queue.c:408
#define RADIO_RX_MODE_ADDRESS_FILTER
The radio reception mode controls address filtering and automatic transmission of acknowledgements in...
Definition: radio.h:204
int tsch_is_locked(void)
Checks if the TSCH lock is set.
uint8_t frame_type
3 bit.
Definition: frame802154.h:153
void tsch_slot_operation_sync(rtimer_clock_t next_slot_start, struct tsch_asn_t *next_slot_asn)
Set global time before starting slot operation, with a rtimer time and an ASN.
Parameters used by the frame802154_create() function.
Definition: frame802154.h:198
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a link-layer address.
Definition: linkaddr.c:63
#define PT_THREAD(name_args)
Declaration of a protothread.
Definition: pt.h:99
void tsch_packet_set_frame_pending(uint8_t *buf, int buf_size)
Set frame pending bit in a packet (whose header was already build)
Definition: tsch-packet.c:467
int tsch_queue_packet_sent(struct tsch_neighbor *n, struct tsch_packet *p, struct tsch_link *link, uint8_t mac_tx_status)
Updates neighbor queue state after a transmission.
Definition: tsch-queue.c:320
#define TSCH_ASN_DIFF(asn1, asn2)
Returns the 32-bit diff between asn1 and asn2.
Definition: tsch-asn.h:82
int linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
Definition: linkaddr.c:69
static void tsch_radio_on(enum tsch_radio_state_on_cmd command)
This function turns on the radio.
int tsch_queue_packet_count(const linkaddr_t *addr)
Returns the number of packets currently a given neighbor queue.
Definition: tsch-queue.c:278
#define TSCH_ASN_INC(asn, inc)
Increment an ASN by inc (32 bits)
Definition: tsch-asn.h:68
uint8_t seq
Sequence number.
Definition: frame802154.h:205
int tsch_packet_get_frame_pending(uint8_t *buf, int buf_size)
Get frame pending bit from a packet.
Definition: tsch-packet.c:474
int ringbufindex_peek_put(const struct ringbufindex *r)
Check if there is space to put an element.
Definition: ringbufindex.c:78
void tsch_disassociate(void)
Leave the TSCH network we are currently in.
Definition: tsch.c:501
Header file for the Packet buffer (packetbuf) management
Include file for the Contiki low-layer network stack (NETSTACK)
struct tsch_packet * tsch_queue_get_unicast_packet_for_any(struct tsch_neighbor **n, struct tsch_link *link)
Gets the head packet of any neighbor queue with zero backoff counter.
Definition: tsch-queue.c:447
unsigned int tsch_security_secure_frame(uint8_t *hdr, uint8_t *outbuf, int hdrlen, int datalen, struct tsch_asn_t *asn)
Protect a frame with encryption and/or MIC.
Stores data about an incoming packet.
Definition: tsch-types.h:146
Header file for the logging system
The MAC layer deferred the transmission for a later time.
Definition: mac.h:91
uint8_t ack_required
1 bit.
Definition: frame802154.h:156
int ringbufindex_put(struct ringbufindex *r)
Put one element to the ring buffer.
Definition: ringbufindex.c:58
void tsch_slot_operation_start(void)
Start actual slot operation.
The ASN is an absolute slot number over 5 bytes.
Definition: tsch-asn.h:48
frame802154_aux_hdr_t aux_hdr
Aux security header.
Definition: frame802154.h:208
int tsch_packet_create_eack(uint8_t *buf, uint16_t buf_len, const linkaddr_t *dest_addr, uint8_t seqno, int16_t drift, int nack)
Construct Enhanced ACK packet.
Definition: tsch-packet.c:93