55#include "sys/critical.h"
60#ifndef TSCH_DEBUG_INIT
61#define TSCH_DEBUG_INIT()
63#ifndef TSCH_DEBUG_INTERRUPT
64#define TSCH_DEBUG_INTERRUPT()
66#ifndef TSCH_DEBUG_RX_EVENT
67#define TSCH_DEBUG_RX_EVENT()
69#ifndef TSCH_DEBUG_TX_EVENT
70#define TSCH_DEBUG_TX_EVENT()
72#ifndef TSCH_DEBUG_SLOT_START
73#define TSCH_DEBUG_SLOT_START()
75#ifndef TSCH_DEBUG_SLOT_END
76#define TSCH_DEBUG_SLOT_END()
80#if (TSCH_MAX_INCOMING_PACKETS & (TSCH_MAX_INCOMING_PACKETS - 1)) != 0
81#error TSCH_MAX_INCOMING_PACKETS must be power of two
85#if TSCH_DEQUEUED_ARRAY_SIZE < QUEUEBUF_NUM
86#error TSCH_DEQUEUED_ARRAY_SIZE must be greater or equal to QUEUEBUF_NUM
88#if (TSCH_DEQUEUED_ARRAY_SIZE & (TSCH_DEQUEUED_ARRAY_SIZE - 1)) != 0
89#error TSCH_DEQUEUED_ARRAY_SIZE must be power of two
94#define SYNC_IE_BOUND ((int32_t)US_TO_RTIMERTICKS(tsch_timing_us[tsch_ts_rx_wait] / 4))
97#if RTIMER_SECOND < (32 * 1024)
98#error "TSCH: RTIMER_SECOND < (32 * 1024)"
100#if CONTIKI_TARGET_COOJA
102#define RTIMER_GUARD 0u
103#elif RTIMER_SECOND >= 200000
104#define RTIMER_GUARD (RTIMER_SECOND / 100000)
106#define RTIMER_GUARD 2u
109enum tsch_radio_state_on_cmd {
110 TSCH_RADIO_CMD_ON_START_OF_TIMESLOT,
111 TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT,
112 TSCH_RADIO_CMD_ON_FORCE,
115enum tsch_radio_state_off_cmd {
116 TSCH_RADIO_CMD_OFF_END_OF_TIMESLOT,
117 TSCH_RADIO_CMD_OFF_WITHIN_TIMESLOT,
118 TSCH_RADIO_CMD_OFF_FORCE,
123struct ringbufindex dequeued_ringbuf;
124struct tsch_packet *dequeued_array[TSCH_DEQUEUED_ARRAY_SIZE];
127struct ringbufindex input_ringbuf;
128struct input_packet input_array[TSCH_MAX_INCOMING_PACKETS];
133clock_time_t tsch_last_sync_time;
136static volatile int tsch_locked = 0;
138static volatile int tsch_lock_requested = 0;
142static int32_t drift_correction = 0;
144static uint8_t is_drift_correction_used;
147static rtimer_clock_t
volatile current_slot_start;
150static volatile int tsch_in_slot_operation = 0;
153uint8_t tsch_current_channel;
154uint8_t tsch_current_channel_offset;
162static struct tsch_link *backup_link = NULL;
167static int burst_link_scheduled = 0;
169int tsch_current_burst_count = 0;
176static struct pt slot_operation_pt;
196 rtimer_clock_t busy_wait_time;
199 tsch_lock_requested = 1;
201 if(tsch_in_slot_operation) {
204 while(tsch_in_slot_operation) {
207 busy_wait_time =
RTIMER_NOW() - busy_wait_time;
212 tsch_lock_requested = 0;
216 snprintf(log->message,
sizeof(log->message),
217 "!get lock delay %u", (
unsigned)busy_wait_time);
224 snprintf(log->message,
sizeof(log->message),
244#if TSCH_WITH_LINK_SELECTOR
246 uint16_t packet_channel_offset = queuebuf_attr(p->qb, PACKETBUF_ATTR_TSCH_CHANNEL_OFFSET);
247 if(packet_channel_offset != 0xffff) {
249 return packet_channel_offset;
253 return link->channel_offset;
267 uint16_t index_of_0, index_of_offset;
268 index_of_0 =
TSCH_ASN_MOD(*asn, tsch_hopping_sequence_length);
269 index_of_offset = (index_of_0 + channel_offset) % tsch_hopping_sequence_length.val;
270 return tsch_hopping_sequence[index_of_offset];
279check_timer_miss(rtimer_clock_t ref_time, rtimer_clock_t offset, rtimer_clock_t now)
281 rtimer_clock_t target = ref_time + offset;
282 int now_has_overflowed = now < ref_time;
283 int target_has_overflowed = target < ref_time;
285 if(now_has_overflowed == target_has_overflowed) {
287 return target <= now;
293 return now_has_overflowed;
301tsch_schedule_slot_operation(
struct rtimer *tm, rtimer_clock_t ref_time, rtimer_clock_t offset,
const char *str)
307 int missed = check_timer_miss(ref_time, offset - RTIMER_GUARD, now);
311 snprintf(log->message,
sizeof(log->message),
313 str, (
int)(now-ref_time), (
int)offset);
316 r =
rtimer_set(tm, ref_time + offset, 1, (
void (*)(
struct rtimer *,
void *))tsch_slot_operation, NULL);
323 RTIMER_BUSYWAIT_UNTIL_ABS(0, ref_time, offset);
330#define TSCH_SCHEDULE_AND_YIELD(pt, tm, ref_time, offset, str) \
332 if(tsch_schedule_slot_operation(tm, ref_time, offset - RTIMER_GUARD, str)) { \
335 RTIMER_BUSYWAIT_UNTIL_ABS(0, ref_time, offset); \
344is_current_channel_in_join_sequence(
struct tsch_link *link)
346#ifdef TSCH_CONF_JOIN_HOPPING_SEQUENCE
349 link->channel_offset);
351 for(i = 0; i <
sizeof(TSCH_JOIN_HOPPING_SEQUENCE); ++i) {
352 if(TSCH_JOIN_HOPPING_SEQUENCE[i] == current_channel) {
373 if(link->link_options & LINK_OPTION_TX) {
375 if(link->link_type == LINK_TYPE_ADVERTISING || link->link_type == LINK_TYPE_ADVERTISING_ONLY) {
377 if(is_current_channel_in_join_sequence(link)) {
383 if(link->link_type != LINK_TYPE_ADVERTISING_ONLY) {
390 if(p == NULL && n == n_broadcast) {
397 if(target_neighbor != NULL) {
398 *target_neighbor = n;
405void update_link_backoff(
struct tsch_link *link) {
407 && (link->link_options & LINK_OPTION_TX)
408 && (link->link_options & LINK_OPTION_SHARED)) {
419 uint64_t uptime_ticks;
422 if(!tsch_is_associated) {
429 uptime_asn = last_sync_asn.ls4b + ((uint64_t)last_sync_asn.ms1b << 32);
431 uptime_ticks = uptime_asn * tsch_timing[tsch_ts_timeslot_length];
435 uptime_ticks += (
clock_time() - tsch_last_sync_time);
454 case TSCH_RADIO_CMD_ON_START_OF_TIMESLOT:
455 if(TSCH_RADIO_ON_DURING_TIMESLOT) {
459 case TSCH_RADIO_CMD_ON_WITHIN_TIMESLOT:
460 if(!TSCH_RADIO_ON_DURING_TIMESLOT) {
464 case TSCH_RADIO_CMD_ON_FORCE:
485 case TSCH_RADIO_CMD_OFF_END_OF_TIMESLOT:
486 if(TSCH_RADIO_ON_DURING_TIMESLOT) {
490 case TSCH_RADIO_CMD_OFF_WITHIN_TIMESLOT:
491 if(!TSCH_RADIO_ON_DURING_TIMESLOT) {
495 case TSCH_RADIO_CMD_OFF_FORCE:
500 NETSTACK_RADIO.off();
519 static uint8_t mac_tx_status;
522 static int dequeued_index;
523 static int packet_ready = 1;
527 TSCH_DEBUG_TX_EVENT();
532 if(dequeued_index != -1) {
533 if(current_packet == NULL || current_packet->qb == NULL) {
538#if LLSEC802154_ENABLED
540 static uint8_t encrypted_packet[TSCH_PACKET_MAX_LEN];
543 static uint8_t packet_len;
545 static uint8_t seqno;
547 static uint8_t do_wait_for_ack;
548 static rtimer_clock_t tx_start_time;
550 static int burst_link_requested;
553 static uint8_t cca_status;
557 packet = queuebuf_dataptr(current_packet->qb);
558 packet_len = queuebuf_datalen(current_packet->qb);
560 do_wait_for_ack = !current_neighbor->is_broadcast;
562 burst_link_requested = 0;
564 && tsch_current_burst_count + 1 < TSCH_BURST_MAX_LEN
566 burst_link_requested = 1;
570 seqno = ((uint8_t *)(packet))[2];
572 if(current_neighbor == n_eb) {
578#if LLSEC802154_ENABLED
579 if(tsch_is_pan_secured) {
582 int with_encryption = queuebuf_attr(current_packet->qb, PACKETBUF_ATTR_SECURITY_LEVEL) & 0x4;
584 packet_len - current_packet->header_len, &tsch_current_asn);
585 if(with_encryption) {
586 packet = encrypted_packet;
592 if(packet_ready && NETSTACK_RADIO.prepare(packet, packet_len) == 0) {
593 static rtimer_clock_t tx_duration;
598 TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, tsch_timing[tsch_ts_cca_offset],
"cca");
599 TSCH_DEBUG_TX_EVENT();
602 RTIMER_BUSYWAIT_UNTIL_ABS(!(cca_status &= NETSTACK_RADIO.channel_clear()),
603 current_slot_start, tsch_timing[tsch_ts_cca_offset] + tsch_timing[tsch_ts_cca]);
604 TSCH_DEBUG_TX_EVENT();
607 if(cca_status == 0) {
613 TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, tsch_timing[tsch_ts_tx_offset] - RADIO_DELAY_BEFORE_TX,
"TxBeforeTx");
614 TSCH_DEBUG_TX_EVENT();
616 mac_tx_status = NETSTACK_RADIO.transmit(packet_len);
619 tx_start_time = current_slot_start + tsch_timing[tsch_ts_tx_offset];
621 tx_duration = TSCH_PACKET_DURATION(packet_len);
623 tx_duration = MIN(tx_duration, tsch_timing[tsch_ts_max_tx]);
628 if(do_wait_for_ack) {
629 uint8_t ackbuf[TSCH_PACKET_MAX_LEN];
631 rtimer_clock_t ack_start_time;
633 struct ieee802154_ies ack_ies;
637#if TSCH_HW_FRAME_FILTERING
644 TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start,
645 tsch_timing[tsch_ts_tx_offset] + tx_duration + tsch_timing[tsch_ts_rx_ack_delay] - RADIO_DELAY_BEFORE_RX,
"TxBeforeAck");
646 TSCH_DEBUG_TX_EVENT();
649 RTIMER_BUSYWAIT_UNTIL_ABS(NETSTACK_RADIO.receiving_packet(),
650 tx_start_time, tx_duration + tsch_timing[tsch_ts_rx_ack_delay] + tsch_timing[tsch_ts_ack_wait] + RADIO_DELAY_BEFORE_DETECT);
651 TSCH_DEBUG_TX_EVENT();
653 ack_start_time =
RTIMER_NOW() - RADIO_DELAY_BEFORE_DETECT;
656 RTIMER_BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(),
657 ack_start_time, tsch_timing[tsch_ts_max_ack]);
658 TSCH_DEBUG_TX_EVENT();
661#if TSCH_HW_FRAME_FILTERING
668 ack_len = NETSTACK_RADIO.read((
void *)ackbuf,
sizeof(ackbuf));
673 is_time_source = current_neighbor != NULL && current_neighbor->is_time_source;
675 &frame, &ack_ies, &ack_hdrlen) == 0) {
679#if LLSEC802154_ENABLED
684 snprintf(log->message,
sizeof(log->message),
685 "!failed to authenticate ACK"));
690 snprintf(log->message,
sizeof(log->message),
691 "!failed to parse ACK"));
698 int32_t eack_time_correction = US_TO_RTIMERTICKS(ack_ies.ie_time_correction);
699 int32_t since_last_timesync =
TSCH_ASN_DIFF(tsch_current_asn, last_sync_asn);
700 if(eack_time_correction > SYNC_IE_BOUND) {
701 drift_correction = SYNC_IE_BOUND;
702 }
else if(eack_time_correction < -SYNC_IE_BOUND) {
703 drift_correction = -SYNC_IE_BOUND;
705 drift_correction = eack_time_correction;
707 if(drift_correction != eack_time_correction) {
709 snprintf(log->message,
sizeof(log->message),
710 "!truncated dr %d %d", (
int)eack_time_correction, (
int)drift_correction);
713 tsch_stats_on_time_synchronization(eack_time_correction);
714 is_drift_correction_used = 1;
717 last_sync_asn = tsch_current_asn;
725 if(burst_link_requested) {
726 burst_link_scheduled = 1;
745 current_packet->transmissions++;
746 current_packet->ret = mac_tx_status;
753 dequeued_array[dequeued_index] = current_packet;
758 if(current_neighbor != NULL && current_neighbor->is_time_source) {
759 tsch_stats_tx_packet(current_neighbor, mac_tx_status, tsch_current_channel);
764 log->tx.mac_tx_status = mac_tx_status;
765 log->tx.num_tx = current_packet->transmissions;
766 log->tx.datalen = queuebuf_datalen(current_packet->qb);
767 log->tx.drift = drift_correction;
768 log->tx.drift_used = is_drift_correction_used;
769 log->tx.is_data = ((((uint8_t *)(queuebuf_dataptr(current_packet->qb)))[0]) & 7) == FRAME802154_DATAFRAME;
770#if LLSEC802154_ENABLED
771 log->tx.sec_level = queuebuf_attr(current_packet->qb, PACKETBUF_ATTR_SECURITY_LEVEL);
773 log->tx.sec_level = 0;
775 linkaddr_copy(&log->tx.dest, queuebuf_addr(current_packet->qb, PACKETBUF_ADDR_RECEIVER));
776 log->tx.seqno = queuebuf_attr(current_packet->qb, PACKETBUF_ATTR_MAC_SEQNO);
783 TSCH_DEBUG_TX_EVENT();
801 static linkaddr_t source_address;
802 static linkaddr_t destination_address;
803 static int16_t input_index;
804 static int input_queue_drop = 0;
808 TSCH_DEBUG_RX_EVENT();
811 if(input_index == -1) {
816 static int32_t estimated_drift;
818 static rtimer_clock_t rx_start_time;
819 static rtimer_clock_t expected_rx_time;
820 static rtimer_clock_t packet_duration;
823 expected_rx_time = current_slot_start + tsch_timing[tsch_ts_tx_offset];
825 rx_start_time = expected_rx_time;
827 current_input = &input_array[input_index];
830 TSCH_SCHEDULE_AND_YIELD(pt, t, current_slot_start, tsch_timing[tsch_ts_rx_offset] - RADIO_DELAY_BEFORE_RX,
"RxBeforeListen");
831 TSCH_DEBUG_RX_EVENT();
835 packet_seen = NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet();
838 RTIMER_BUSYWAIT_UNTIL_ABS((packet_seen = (NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet())),
839 current_slot_start, tsch_timing[tsch_ts_rx_offset] + tsch_timing[tsch_ts_rx_wait] + RADIO_DELAY_BEFORE_DETECT);
845 TSCH_DEBUG_RX_EVENT();
847 rx_start_time =
RTIMER_NOW() - RADIO_DELAY_BEFORE_DETECT;
850 RTIMER_BUSYWAIT_UNTIL_ABS(!NETSTACK_RADIO.receiving_packet(),
851 current_slot_start, tsch_timing[tsch_ts_rx_offset] + tsch_timing[tsch_ts_rx_wait] + tsch_timing[tsch_ts_max_tx]);
852 TSCH_DEBUG_RX_EVENT();
855 if(NETSTACK_RADIO.pending_packet()) {
856 static int frame_valid;
857 static int header_len;
863 current_input->len = NETSTACK_RADIO.read((
void *)current_input->payload, TSCH_PACKET_MAX_LEN);
865 current_input->rx_asn = tsch_current_asn;
866 current_input->rssi = (signed)radio_last_rssi;
867 current_input->channel = tsch_current_channel;
868 header_len =
frame802154_parse((uint8_t *)current_input->payload, current_input->len, &frame);
869 frame_valid = header_len > 0 &&
870 frame802154_check_dest_panid(&frame) &&
871 frame802154_extract_linkaddr(&frame, &source_address, &destination_address);
873#if TSCH_RESYNC_WITH_SFD_TIMESTAMPS
878 packet_duration = TSCH_PACKET_DURATION(current_input->len);
880 packet_duration = MIN(packet_duration, tsch_timing[tsch_ts_max_tx]);
884 snprintf(log->message,
sizeof(log->message),
885 "!failed to parse frame %u %u", header_len, current_input->len));
892 snprintf(log->message,
sizeof(log->message),
893 "!discarding frame with type %u, len %u", frame.
fcf.
frame_type, current_input->len));
898#if LLSEC802154_ENABLED
903 &frame, &source_address, &tsch_current_asn)) {
907 snprintf(log->message,
sizeof(log->message),
908 "!failed to authenticate frame %u", current_input->len));
923 estimated_drift = RTIMER_CLOCK_DIFF(expected_rx_time, rx_start_time);
924 tsch_stats_on_time_synchronization(estimated_drift);
926#if TSCH_TIMESYNC_REMOVE_JITTER
928 if(ABS(estimated_drift) <= TSCH_TIMESYNC_MEASUREMENT_ERROR) {
930 }
else if(estimated_drift > 0) {
931 estimated_drift -= TSCH_TIMESYNC_MEASUREMENT_ERROR;
933 estimated_drift += TSCH_TIMESYNC_MEASUREMENT_ERROR;
937#ifdef TSCH_CALLBACK_DO_NACK
939 do_nack = TSCH_CALLBACK_DO_NACK(current_link,
940 &source_address, &destination_address);
945 static uint8_t ack_buf[TSCH_PACKET_MAX_LEN];
950 &source_address, frame.
seq, (int16_t)RTIMERTICKS_TO_US(estimated_drift), do_nack);
953#if LLSEC802154_ENABLED
954 if(tsch_is_pan_secured) {
961 NETSTACK_RADIO.prepare((
const void *)ack_buf, ack_len);
964 TSCH_SCHEDULE_AND_YIELD(pt, t, rx_start_time,
965 packet_duration + tsch_timing[tsch_ts_tx_ack_delay] - RADIO_DELAY_BEFORE_TX,
"RxBeforeAck");
966 TSCH_DEBUG_RX_EVENT();
967 NETSTACK_RADIO.transmit(ack_len);
977 if(n != NULL && n->is_time_source) {
978 int32_t since_last_timesync =
TSCH_ASN_DIFF(tsch_current_asn, last_sync_asn);
980 last_sync_asn = tsch_current_asn;
983 drift_correction = -estimated_drift;
984 is_drift_correction_used = 1;
996 tsch_stats_rx_packet(n, current_input->rssi, radio_last_lqi, tsch_current_channel);
1003 log->rx.datalen = current_input->len;
1004 log->rx.drift = drift_correction;
1005 log->rx.drift_used = is_drift_correction_used;
1006 log->rx.is_data = frame.
fcf.
frame_type == FRAME802154_DATAFRAME;
1008 log->rx.estimated_drift = estimated_drift;
1009 log->rx.seqno = frame.
seq;
1021 if(input_queue_drop != 0) {
1023 snprintf(log->message,
sizeof(log->message),
1024 "!queue full skipped %u", input_queue_drop);
1026 input_queue_drop = 0;
1030 TSCH_DEBUG_RX_EVENT();
1040 TSCH_DEBUG_INTERRUPT();
1044 while(tsch_is_associated) {
1046 if(current_link == NULL || tsch_lock_requested) {
1050 snprintf(log->message,
sizeof(log->message),
1051 "!skipped slot %u %u %u",
1053 tsch_lock_requested,
1054 current_link == NULL);
1059 TSCH_DEBUG_SLOT_START();
1060 tsch_in_slot_operation = 1;
1062 tsch_stats_sample_rssi();
1064 drift_correction = 0;
1065 is_drift_correction_used = 0;
1067 current_packet = get_packet_and_neighbor_for_link(current_link, ¤t_neighbor);
1068 uint8_t do_skip_best_link = 0;
1069 if(current_packet == NULL && backup_link != NULL) {
1073 if(!(current_link->link_options & LINK_OPTION_RX)
1074 || backup_link->slotframe_handle < current_link->slotframe_handle) {
1075 do_skip_best_link = 1;
1079 if(do_skip_best_link) {
1081 update_link_backoff(current_link);
1083 current_link = backup_link;
1084 current_packet = get_packet_and_neighbor_for_link(current_link, ¤t_neighbor);
1086 is_active_slot = current_packet != NULL || (current_link->link_options & LINK_OPTION_RX);
1087 if(is_active_slot) {
1090 if(burst_link_scheduled) {
1092 burst_link_scheduled = 0;
1095 tsch_current_channel_offset = tsch_get_channel_offset(current_link, current_packet);
1103 if(current_packet != NULL) {
1109 static struct pt slot_tx_pt;
1113 static struct pt slot_rx_pt;
1119 burst_link_scheduled = 0;
1121 TSCH_DEBUG_SLOT_END();
1126 if(tsch_is_coordinator) {
1129 last_sync_asn = tsch_current_asn;
1134 if(!tsch_is_coordinator && (
TSCH_ASN_DIFF(tsch_current_asn, last_sync_asn) >
1135 (100 * TSCH_CLOCK_TO_SLOTS(TSCH_DESYNC_THRESHOLD / 100, tsch_timing[tsch_ts_timeslot_length])))) {
1137 snprintf(log->message,
sizeof(log->message),
1138 "! leaving the network, last sync %u",
1145 uint16_t timeslot_diff = 0;
1146 rtimer_clock_t prev_slot_start;
1148 rtimer_clock_t time_to_next_active_slot;
1151 update_link_backoff(current_link);
1155 if(burst_link_scheduled && current_link != NULL) {
1159 tsch_current_burst_count++;
1163 if(current_link == NULL) {
1170 tsch_current_burst_count = 0;
1177 time_to_next_active_slot = timeslot_diff * tsch_timing[tsch_ts_timeslot_length] + drift_correction;
1179 drift_correction = 0;
1180 is_drift_correction_used = 0;
1182 prev_slot_start = current_slot_start;
1183 current_slot_start += time_to_next_active_slot;
1184 }
while(!tsch_schedule_slot_operation(t, prev_slot_start, time_to_next_active_slot,
"main"));
1187 tsch_in_slot_operation = 0;
1191 PT_END(&slot_operation_pt);
1199 static struct rtimer slot_operation_timer;
1200 rtimer_clock_t time_to_next_active_slot;
1201 rtimer_clock_t prev_slot_start;
1204 uint16_t timeslot_diff;
1207 if(current_link == NULL) {
1215 time_to_next_active_slot = timeslot_diff * tsch_timing[tsch_ts_timeslot_length];
1219 prev_slot_start = current_slot_start;
1220 current_slot_start += time_to_next_active_slot;
1221 }
while(!tsch_schedule_slot_operation(&slot_operation_timer, prev_slot_start, time_to_next_active_slot,
"assoc"));
1231 current_slot_start = next_slot_start;
1232 tsch_current_asn = *next_slot_asn;
1234 last_sync_asn = tsch_current_asn;
1237 current_link = NULL;
A MAC framer for IEEE 802.15.4.
clock_time_t clock_time(void)
Get the current clock time.
void watchdog_periodic(void)
Writes the WDT clear sequence.
#define CLOCK_SECOND
A second, measured in system clock time.
static void critical_exit(int_master_status_t status)
Exit a critical section and restore the master interrupt.
static int_master_status_t critical_enter()
Enter a critical section.
int frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
Parses an input frame.
uint32_t int_master_status_t
Master interrupt state representation data type.
linkaddr_t linkaddr_node_addr
The link-layer address of the node.
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a link-layer address.
bool linkaddr_cmp(const linkaddr_t *addr1, const linkaddr_t *addr2)
Compare two link-layer addresses.
const linkaddr_t linkaddr_null
The null link-layer address.
void process_poll(struct process *p)
Request a process to be polled.
#define PT_YIELD(pt)
Yield from the current protothread.
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
#define PT_THREAD(name_args)
Declaration of a protothread.
#define PT_END(pt)
Declare the end of a protothread.
#define PT_SPAWN(pt, child, thread)
Spawn a child protothread and wait until it exits.
#define RADIO_RX_MODE_ADDRESS_FILTER
Enable address-based frame filtering.
int radio_value_t
Each radio has a set of parameters that designate the current configuration and state of the radio.
@ RADIO_PARAM_LAST_PACKET_TIMESTAMP
Last packet timestamp, of type rtimer_clock_t.
@ RADIO_PARAM_LAST_RSSI
The RSSI value of the last received packet.
@ RADIO_PARAM_RX_MODE
Radio receiver mode determines if the radio has address filter (RADIO_RX_MODE_ADDRESS_FILTER) and aut...
@ RADIO_PARAM_CHANNEL
Channel used for radio communication.
@ RADIO_PARAM_LAST_LINK_QUALITY
Link quality indicator of the last received packet.
@ RADIO_TX_OK
TX was successful and where an ACK was requested one was received.
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.
#define RTIMER_NOW()
Get the current clock time.
@ RTIMER_OK
rtimer task is scheduled successfully
struct tsch_neighbor * tsch_queue_get_nbr(const linkaddr_t *addr)
Get a TSCH neighbor.
void tsch_schedule_keepalive(int immediate)
Schedule a keep-alive transmission within [timeout*0.9, timeout[ Can be called from an interrupt.
int tsch_packet_update_eb(uint8_t *buf, int buf_size, uint8_t tsch_sync_ie_offset)
Update ASN in EB packet.
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.
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,...
uint64_t tsch_get_network_uptime_ticks(void)
Get the time, in clock ticks, since the TSCH network was started.
static char tsch_rx_slot(struct pt *pt, struct rtimer *t)
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.
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.
#define TSCH_ASN_INC(asn, inc)
Increment an ASN by inc (32 bits)
#define TSCH_ASN_DIFF(asn1, asn2)
Returns the 32-bit diff between asn1 and asn2.
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.
static void tsch_radio_on(enum tsch_radio_state_on_cmd command)
This function turns on the radio.
int tsch_packet_get_frame_pending(uint8_t *buf, int buf_size)
Get frame pending bit from a packet.
unsigned int tsch_security_mic_len(const frame802154_t *frame)
Return MIC length.
int tsch_queue_nbr_packet_count(const struct tsch_neighbor *n)
Returns the number of packets currently a given neighbor queue (by pointer)
#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)
int tsch_get_lock(void)
Takes the TSCH lock.
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.
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.
static void tsch_radio_off(enum tsch_radio_state_off_cmd command)
This function turns off the radio.
void tsch_release_lock(void)
Releases the TSCH lock.
int32_t tsch_timesync_adaptive_compensate(rtimer_clock_t delta_ticks)
Computes time compensation for a given point in the future.
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.
#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.
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.
static char tsch_tx_slot(struct pt *pt, struct rtimer *t)
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.
int tsch_is_locked(void)
Checks if the TSCH lock is set.
static uint8_t tsch_calculate_channel(struct tsch_asn_t *asn, uint16_t channel_offset)
Returns a 802.15.4 channel from an ASN and channel offset.
void tsch_packet_set_frame_pending(uint8_t *buf, int buf_size)
Set frame pending bit in a packet (whose header was already build)
linkaddr_t * tsch_queue_get_nbr_address(const struct tsch_neighbor *n)
Get the address of a neighbor.
void tsch_disassociate(void)
Leave the TSCH network we are currently in.
void tsch_timesync_update(struct tsch_neighbor *n, uint16_t time_delta_asn, int32_t drift_correction)
Updates timesync information for a given neighbor.
void tsch_slot_operation_start(void)
Start actual slot operation.
Header file for the logging system.
@ MAC_TX_COLLISION
The MAC layer did not get an acknowledgement for the packet.
@ MAC_TX_OK
The MAC layer transmission was OK.
@ MAC_TX_NOACK
The MAC layer deferred the transmission for a later time.
@ MAC_TX_ERR_FATAL
The MAC layer transmission could not be performed because of insufficient queue space,...
@ MAC_TX_ERR
The MAC layer transmission could not be performed because of a fatal error.
Include file for the Contiki low-layer network stack (NETSTACK)
Header file for the Packet buffer (packetbuf) management.
Header file for the Packet queue buffer management.
Header file for the radio API.
int ringbufindex_put(struct ringbufindex *r)
Put one element to the ring buffer.
int ringbufindex_peek_put(const struct ringbufindex *r)
Check if there is space to put an element.
frame802154_scf_t security_control
Security control bitfield.
uint8_t ack_required
1 bit.
uint8_t security_level
3 bit.
Parameters used by the frame802154_create() function.
uint8_t seq
Sequence number.
frame802154_aux_hdr_t aux_hdr
Aux security header.
uint8_t src_addr[8]
Source address.
frame802154_fcf_t fcf
Frame control field
Representation of a real-time task.
The ASN is an absolute slot number over 5 bytes.
An IEEE 802.15.4-2015 TSCH link (also called cell or slot)
TSCH neighbor information.
Main API declarations for TSCH.