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