53#include "net/nbr-table.h"
54#include "net/link-stats.h"
66#if FRAME802154_VERSION < FRAME802154_IEEE802154_2015
67#error TSCH: FRAME802154_VERSION must be at least FRAME802154_IEEE802154_2015
72#define LOG_MODULE "TSCH"
73#define LOG_LEVEL LOG_LEVEL_MAC
77static linkaddr_t last_eb_nbr_addr;
79static uint8_t last_eb_nbr_jp;
83#if TSCH_AUTOSELECT_TIME_SOURCE
84int best_neighbor_eb_count;
89NBR_TABLE(
struct eb_stat, eb_stats);
93uint8_t tsch_hopping_sequence[TSCH_HOPPING_SEQUENCE_MAX_LEN];
97static const uint16_t *tsch_default_timing_us;
99uint16_t tsch_timing_us[tsch_ts_elements_count];
101rtimer_clock_t tsch_timing[tsch_ts_elements_count];
103#if LINKADDR_SIZE == 8
105const linkaddr_t tsch_broadcast_address = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
107const linkaddr_t tsch_eb_address = { { 0, 0, 0, 0, 0, 0, 0, 0 } };
109const linkaddr_t tsch_broadcast_address = { { 0xff, 0xff } };
110const linkaddr_t tsch_eb_address = { { 0, 0 } };
114int tsch_is_started = 0;
116int tsch_is_initialized = 0;
118int tsch_is_coordinator = 0;
120int tsch_is_associated = 0;
122int tsch_association_count = 0;
124int tsch_is_pan_secured = LLSEC802154_ENABLED;
129uint8_t tsch_join_priority;
131static clock_time_t tsch_current_eb_period;
133static clock_time_t tsch_current_ka_timeout;
136enum tsch_keepalive_status {
137 KEEPALIVE_SCHEDULING_UNCHANGED,
138 KEEPALIVE_SCHEDULE_OR_STOP,
139 KEEPALIVE_SEND_IMMEDIATELY,
142static volatile enum tsch_keepalive_status keepalive_status;
145static struct ctimer keepalive_timer;
148unsigned long tx_count;
149unsigned long rx_count;
150unsigned long sync_count;
151int32_t min_drift_seen;
152int32_t max_drift_seen;
156PROCESS(tsch_process,
"main process");
157PROCESS(tsch_send_eb_process,
"send EB process");
158PROCESS(tsch_pending_events_process,
"pending events process");
169 if(tsch_is_coordinator != enable) {
170 tsch_is_associated = 0;
172 tsch_is_coordinator = enable;
180 tsch_is_pan_secured = LLSEC802154_ENABLED && enable;
186 tsch_join_priority = jp;
192 tsch_current_ka_timeout = timeout;
199 tsch_current_eb_period = MIN(period, TSCH_MAX_EB_PERIOD);
206 frame802154_set_pan_id(0xffff);
215 tsch_join_priority = 0xff;
219 tsch_default_timing_us = TSCH_DEFAULT_TIMESLOT_TIMING;
220 for(i = 0; i < tsch_ts_elements_count; i++) {
221 tsch_timing_us[i] = tsch_default_timing_us[i];
222 tsch_timing[i] = US_TO_RTIMERTICKS(tsch_timing_us[i]);
224#ifdef TSCH_CALLBACK_LEAVING_NETWORK
225 TSCH_CALLBACK_LEAVING_NETWORK();
228#if TSCH_AUTOSELECT_TIME_SOURCE
229 struct eb_stat *stat;
230 best_neighbor_eb_count = 0;
232 stat = nbr_table_head(eb_stats);
233 while(stat != NULL) {
234 nbr_table_remove(eb_stats, stat);
235 stat = nbr_table_next(eb_stats, stat);
239 keepalive_status = KEEPALIVE_SCHEDULING_UNCHANGED;
249resynchronize(
const linkaddr_t *original_time_source_addr)
253 if(ts_addr != NULL && !
linkaddr_cmp(ts_addr, original_time_source_addr)) {
255 LOG_INFO(
"time source has been changed to ");
256 LOG_INFO_LLADDR(ts_addr);
262 LOG_WARN(
"not able to re-synchronize, received no EB from other neighbors\n");
263 if(sync_count == 0) {
269 LOG_WARN(
"re-synchronizing on ");
270 LOG_WARN_LLADDR(&last_eb_nbr_addr);
274 tsch_join_priority = last_eb_nbr_jp + 1;
285keepalive_packet_sent(
void *ptr,
int status,
int transmissions)
287 int schedule_next_keepalive = 1;
289 link_stats_packet_sent(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), status, transmissions);
291#ifdef TSCH_CALLBACK_KA_SENT
292 TSCH_CALLBACK_KA_SENT(status, transmissions);
294 LOG_INFO(
"KA sent to ");
295 LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
296 LOG_INFO_(
", st %d-%d\n", status, transmissions);
300 schedule_next_keepalive = !resynchronize(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
303 if(schedule_next_keepalive) {
310keepalive_send(
void *ptr)
315 if(tsch_is_associated) {
321 packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, destination);
322 NETSTACK_MAC.
send(keepalive_packet_sent, NULL);
323 LOG_INFO(
"sending KA to ");
324 LOG_INFO_LLADDR(destination);
327 LOG_ERR(
"no timesource - KA not sent\n");
337 keepalive_status = KEEPALIVE_SEND_IMMEDIATELY;
338 }
else if(keepalive_status != KEEPALIVE_SEND_IMMEDIATELY) {
340 keepalive_status = KEEPALIVE_SCHEDULE_OR_STOP;
346tsch_keepalive_process_pending(
void)
348 if(keepalive_status != KEEPALIVE_SCHEDULING_UNCHANGED) {
350 enum tsch_keepalive_status scheduled_status = keepalive_status;
351 keepalive_status = KEEPALIVE_SCHEDULING_UNCHANGED;
353 if(!tsch_is_coordinator && tsch_is_associated) {
354 switch(scheduled_status) {
355 case KEEPALIVE_SEND_IMMEDIATELY:
357 keepalive_send(NULL);
360 case KEEPALIVE_SCHEDULE_OR_STOP:
361 if(tsch_current_ka_timeout > 0) {
364 if(tsch_current_ka_timeout >= 10) {
365 delay = (tsch_current_ka_timeout - tsch_current_ka_timeout / 10)
366 + random_rand() % (tsch_current_ka_timeout / 10);
368 delay = tsch_current_ka_timeout - 1;
370 ctimer_set(&keepalive_timer, delay, keepalive_send, NULL);
394 struct ieee802154_ies eb_ies;
397 &frame, &eb_ies, NULL, 1)) {
406 last_eb_nbr_jp = eb_ies.ie_join_priority;
409#if TSCH_AUTOSELECT_TIME_SOURCE
410 if(!tsch_is_coordinator) {
412 struct eb_stat *stat = (
struct eb_stat *)nbr_table_get_from_lladdr(eb_stats, (linkaddr_t *)&frame.
src_addr);
414 stat = (
struct eb_stat *)nbr_table_add_lladdr(eb_stats, (linkaddr_t *)&frame.
src_addr, NBR_TABLE_REASON_MAC, NULL);
418 stat->jp = eb_ies.ie_join_priority;
419 best_neighbor_eb_count = MAX(best_neighbor_eb_count, stat->rx_count);
422 struct eb_stat *best_stat = NULL;
423 stat = nbr_table_head(eb_stats);
424 while(stat != NULL) {
426 if(stat->rx_count > best_neighbor_eb_count / 2) {
427 if(best_stat == NULL ||
428 stat->jp < best_stat->jp) {
432 stat = nbr_table_next(eb_stats, stat);
435 if(best_stat != NULL) {
437 tsch_join_priority = best_stat->jp + 1;
443 if(eb_ies.ie_join_priority == 0) {
450 int32_t asn_diff =
TSCH_ASN_DIFF(current_input->rx_asn, eb_ies.ie_asn);
453 LOG_WARN(
"! ASN drifted by %"PRId32
", leaving the network\n", asn_diff);
457 if(eb_ies.ie_join_priority >= TSCH_MAX_JOIN_PRIORITY) {
459 LOG_WARN(
"! EB JP too high %u, leaving the network\n",
460 eb_ies.ie_join_priority);
463#if TSCH_AUTOSELECT_TIME_SOURCE
465 if(tsch_join_priority != eb_ies.ie_join_priority + 1) {
466 LOG_INFO(
"update JP from EB %u -> %u\n",
467 tsch_join_priority, eb_ies.ie_join_priority + 1);
468 tsch_join_priority = eb_ies.ie_join_priority + 1;
474 if(eb_ies.ie_channel_hopping_sequence_id != 0) {
475 if(eb_ies.ie_hopping_sequence_len != tsch_hopping_sequence_length.val
476 || memcmp((uint8_t *)tsch_hopping_sequence, eb_ies.ie_hopping_sequence_list, tsch_hopping_sequence_length.val)) {
477 if(eb_ies.ie_hopping_sequence_len <=
sizeof(tsch_hopping_sequence)) {
478 memcpy((uint8_t *)tsch_hopping_sequence, eb_ies.ie_hopping_sequence_list,
479 eb_ies.ie_hopping_sequence_len);
482 LOG_WARN(
"Updating TSCH hopping sequence from EB\n");
484 LOG_WARN(
"parse_eb: Hopping sequence too long (%u)\n",
485 eb_ies.ie_hopping_sequence_len);
495tsch_rx_process_pending()
500 struct input_packet *current_input = &input_array[input_index];
502 uint8_t ret =
frame802154_parse(current_input->payload, current_input->len, &frame);
503 int is_data = ret && frame.
fcf.
frame_type == FRAME802154_DATAFRAME;
511 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, current_input->rssi);
512 packetbuf_set_attr(PACKETBUF_ATTR_CHANNEL, current_input->channel);
519 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, current_input->rssi);
520 packetbuf_set_attr(PACKETBUF_ATTR_CHANNEL, current_input->channel);
521 link_stats_input_callback((
const linkaddr_t *)frame.
src_addr);
524 eb_input(current_input);
534tsch_tx_process_pending(
void)
536 uint16_t num_packets_freed = 0;
537 int16_t dequeued_index;
540 struct tsch_packet *p = dequeued_array[dequeued_index];
542 queuebuf_to_packetbuf(p->qb);
543 LOG_INFO(
"packet sent to ");
544 LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER));
545 LOG_INFO_(
", seqno %u, status %d, tx %d\n",
546 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO), p->ret, p->transmissions);
548 mac_call_sent_callback(p->sent, p->ptr, p->ret, p->transmissions);
556 if(num_packets_freed > 0) {
564tsch_start_coordinator(
void)
566 frame802154_set_pan_id(IEEE802154_PANID);
568 memcpy(tsch_hopping_sequence, TSCH_DEFAULT_HOPPING_SEQUENCE,
sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE));
570#if TSCH_SCHEDULE_WITH_6TISCH_MINIMAL
574 tsch_is_associated = 1;
575 tsch_join_priority = 0;
577 LOG_INFO(
"starting as coordinator, PAN ID %x, asn-%x.%"PRIx32
"\n",
578 frame802154_get_pan_id(), tsch_current_asn.ms1b, tsch_current_asn.ls4b);
588 if(tsch_is_associated == 1) {
589 tsch_is_associated = 0;
597tsch_associate(
const struct input_packet *input_eb, rtimer_clock_t timestamp)
600 struct ieee802154_ies ies;
605 &frame, &ies, &hdrlen, 0) == 0) {
606 LOG_DBG(
"! failed to parse packet as EB while scanning (len %u)\n",
611 tsch_current_asn = ies.ie_asn;
612 tsch_join_priority = ies.ie_join_priority + 1;
614#if TSCH_JOIN_SECURED_ONLY
616 LOG_ERR(
"! parse_eb: EB is not secured\n");
620#if LLSEC802154_ENABLED
623 &frame, (linkaddr_t*)&frame.
src_addr, &tsch_current_asn)) {
624 LOG_ERR(
"! parse_eb: failed to authenticate\n");
629#if !LLSEC802154_ENABLED
631 LOG_ERR(
"! parse_eb: we do not support security, but EB is secured\n");
636#if TSCH_JOIN_MY_PANID_ONLY
638 if(frame.
src_pid != IEEE802154_PANID) {
639 LOG_ERR(
"! parse_eb: PAN ID %x != %x\n", frame.
src_pid, IEEE802154_PANID);
645 if(ies.ie_join_priority == 0xff) {
646 LOG_ERR(
"! parse_eb: no join priority\n");
651 for(i = 0; i < tsch_ts_elements_count; i++) {
652 if(ies.ie_tsch_timeslot_id == 0) {
653 tsch_timing_us[i] = tsch_default_timing_us[i];
655 tsch_timing_us[i] = ies.ie_tsch_timeslot[i];
657 tsch_timing[i] = US_TO_RTIMERTICKS(tsch_timing_us[i]);
661 if(ies.ie_channel_hopping_sequence_id == 0) {
662 memcpy(tsch_hopping_sequence, TSCH_DEFAULT_HOPPING_SEQUENCE,
sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE));
665 if(ies.ie_hopping_sequence_len <=
sizeof(tsch_hopping_sequence)) {
666 memcpy(tsch_hopping_sequence, ies.ie_hopping_sequence_list, ies.ie_hopping_sequence_len);
669 LOG_ERR(
"! parse_eb: hopping sequence too long (%u)\n", ies.ie_hopping_sequence_len);
674#if TSCH_CHECK_TIME_AT_ASSOCIATION > 0
676 uint32_t expected_asn = 4096 * TSCH_CLOCK_TO_SLOTS(
clock_time() / 4096, tsch_timing_timeslot_length);
677 int32_t asn_threshold = TSCH_CHECK_TIME_AT_ASSOCIATION * 60ul * TSCH_CLOCK_TO_SLOTS(
CLOCK_SECOND, tsch_timing_timeslot_length);
678 int32_t asn_diff = (int32_t)tsch_current_asn.ls4b - expected_asn;
679 if(asn_diff > asn_threshold) {
680 LOG_ERR(
"! EB ASN rejected %lx %lx %ld\n",
681 tsch_current_asn.ls4b, expected_asn, asn_diff);
686#if TSCH_INIT_SCHEDULE_FROM_EB
688 if(ies.ie_tsch_slotframe_and_link.num_slotframes == 0) {
689#if TSCH_SCHEDULE_WITH_6TISCH_MINIMAL
690 LOG_INFO(
"parse_eb: no schedule, setting up minimal schedule\n");
693 LOG_INFO(
"parse_eb: no schedule\n");
699 int num_links = ies.ie_tsch_slotframe_and_link.num_links;
700 if(num_links <= FRAME802154E_IE_MAX_LINKS) {
703 ies.ie_tsch_slotframe_and_link.slotframe_handle,
704 ies.ie_tsch_slotframe_and_link.slotframe_size);
705 for(i = 0; i < num_links; i++) {
707 ies.ie_tsch_slotframe_and_link.links[i].link_options,
708 LINK_TYPE_ADVERTISING, &tsch_broadcast_address,
709 ies.ie_tsch_slotframe_and_link.links[i].timeslot,
710 ies.ie_tsch_slotframe_and_link.links[i].channel_offset, 1);
713 LOG_ERR(
"! parse_eb: too many links in schedule (%u)\n", num_links);
719 if(tsch_join_priority < TSCH_MAX_JOIN_PRIORITY) {
729 frame802154_set_pan_id(frame.
src_pid);
735 tsch_is_associated = 1;
747 if(ies.ie_join_priority == 0) {
751#ifdef TSCH_CALLBACK_JOINING_NETWORK
752 TSCH_CALLBACK_JOINING_NETWORK();
755 tsch_association_count++;
756 LOG_INFO(
"association done (%u), sec %u, PAN ID %x, asn-%x.%"PRIx32
", jp %u, timeslot id %u, hopping id %u, slotframe len %u with %u links, from ",
757 tsch_association_count,
760 tsch_current_asn.ms1b, tsch_current_asn.ls4b, tsch_join_priority,
761 ies.ie_tsch_timeslot_id,
762 ies.ie_channel_hopping_sequence_id,
763 ies.ie_tsch_slotframe_and_link.slotframe_size,
764 ies.ie_tsch_slotframe_and_link.num_links);
765 LOG_INFO_LLADDR((
const linkaddr_t *)&frame.
src_addr);
771 LOG_ERR(
"! did not associate.\n");
786 static struct etimer scan_timer;
788 static clock_time_t current_channel_since;
795 while(!tsch_is_associated && !tsch_is_coordinator) {
797 static uint8_t current_channel = 0;
801 int is_packet_pending = 0;
805 if(current_channel == 0 || now_time - current_channel_since > TSCH_CHANNEL_SCAN_DURATION) {
807 uint8_t scan_channel = TSCH_JOIN_HOPPING_SEQUENCE[
808 random_rand() %
sizeof(TSCH_JOIN_HOPPING_SEQUENCE)];
811 current_channel = scan_channel;
812 LOG_INFO(
"scanning on channel %u\n", scan_channel);
814 current_channel_since = now_time;
820 is_packet_pending = NETSTACK_RADIO.pending_packet();
821 if(!is_packet_pending && NETSTACK_RADIO.receiving_packet()) {
824 RTIMER_BUSYWAIT_UNTIL_ABS((is_packet_pending = NETSTACK_RADIO.pending_packet()), t0,
RTIMER_SECOND / 100);
827 if(is_packet_pending) {
830 input_eb.len = NETSTACK_RADIO.read(input_eb.payload, TSCH_PACKET_MAX_LEN);
832 if(input_eb.len > 0) {
838 LOG_INFO(
"scan: received packet (%u bytes) on channel %u\n", input_eb.len, current_channel);
842 tsch_associate(&input_eb, t0);
844 LOG_WARN(
"scan: dropping packet, timestamp too far from current time %u %u\n",
852 if(tsch_is_associated) {
854 NETSTACK_RADIO.off();
855 }
else if(!tsch_is_coordinator) {
869 static struct pt scan_pt;
875 while(!tsch_is_associated) {
876 if(tsch_is_coordinator) {
878 tsch_start_coordinator();
892 LOG_WARN(
"leaving the network, stats: tx %lu, rx %lu, sync %lu\n",
893 tx_count, rx_count, sync_count);
906 static struct etimer eb_timer;
912 while(!tsch_is_associated) {
918 if(!tsch_is_coordinator) {
919 etimer_set(&eb_timer, TSCH_EB_PERIOD ? random_rand() % TSCH_EB_PERIOD : 0);
926 if(!tsch_is_associated) {
927 LOG_DBG(
"skip sending EB: not joined a TSCH network\n");
928 }
else if(tsch_current_eb_period <= 0) {
929 LOG_DBG(
"skip sending EB: EB period disabled\n");
930#ifdef TSCH_RPL_CHECK_DODAG_JOINED
931 }
else if(!TSCH_RPL_CHECK_DODAG_JOINED()) {
933 LOG_DBG(
"skip sending EB: not joined a routing DAG\n");
937 LOG_DBG(
"skip sending EB: in the leaf mode\n");
940 LOG_DBG(
"skip sending EB: already queued\n");
943 uint8_t tsch_sync_ie_offset;
949 LOG_ERR(
"! could not enqueue EB packet\n");
951 LOG_INFO(
"Enqueuing EB packet %u %u\n",
953 p->tsch_sync_ie_offset = tsch_sync_ie_offset;
954 p->header_len = hdr_len;
958 if(tsch_current_eb_period > 0) {
961 delay = (tsch_current_eb_period - tsch_current_eb_period / 4)
962 + random_rand() % (tsch_current_eb_period / 4);
964 delay = TSCH_EB_PERIOD;
980 tsch_rx_process_pending();
981 tsch_tx_process_pending();
983 tsch_keepalive_process_pending();
984#ifdef TSCH_CALLBACK_SELECT_CHANNELS
985 TSCH_CALLBACK_SELECT_CHANNELS();
1003#if TSCH_DYNAMIC_TIMESLOT_TEMPLATE
1005 if(TSCH_DEFAULT_TIMESLOT_TIMING == NULL) {
1006 LOG_ERR(
"! platform does not provide a timeslot timing template.\n");
1012 if(NETSTACK_RADIO.get_value(RADIO_CONST_MAX_PAYLOAD_LEN, &radio_max_payload_len) !=
RADIO_RESULT_OK) {
1013 LOG_ERR(
"! radio does not support getting RADIO_CONST_MAX_PAYLOAD_LEN. Abort init.\n");
1019 LOG_ERR(
"! radio does not support getting RADIO_PARAM_RX_MODE. Abort init.\n");
1023 radio_rx_mode &= ~RADIO_RX_MODE_ADDRESS_FILTER;
1025 radio_rx_mode &= ~RADIO_RX_MODE_AUTOACK;
1029 LOG_ERR(
"! radio does not support setting required RADIO_PARAM_RX_MODE. Abort init.\n");
1035 LOG_ERR(
"! radio does not support getting RADIO_PARAM_TX_MODE. Abort init.\n");
1039 radio_tx_mode &= ~RADIO_TX_MODE_SEND_ON_CCA;
1041 LOG_ERR(
"! radio does not support setting required RADIO_PARAM_TX_MODE. Abort init.\n");
1046 LOG_ERR(
"! radio does not support setting channel. Abort init.\n");
1051 LOG_ERR(
"! radio does not support getting last packet timestamp. Abort init.\n");
1055 if(TSCH_HOPPING_SEQUENCE_MAX_LEN <
sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)) {
1056 LOG_ERR(
"! TSCH_HOPPING_SEQUENCE_MAX_LEN < sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE). Abort init.\n");
1061#if TSCH_AUTOSELECT_TIME_SOURCE
1062 nbr_table_register(eb_stats, NULL);
1072 tsch_is_initialized = 1;
1094 const linkaddr_t *
addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
1095 uint8_t max_transmissions = 0;
1097 if(!tsch_is_associated) {
1098 if(!tsch_is_initialized) {
1099 LOG_WARN(
"! not initialized (see earlier logs), drop outgoing packet\n");
1101 LOG_WARN(
"! not associated, drop outgoing packet\n");
1104 mac_call_sent_callback(sent, ptr, ret, 1);
1111 packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
1116 addr = &tsch_broadcast_address;
1119 packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME);
1121#if LLSEC802154_ENABLED
1127 max_transmissions = packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS);
1128 if(max_transmissions == 0) {
1130 max_transmissions = TSCH_MAC_MAX_FRAME_RETRIES + 1;
1133 if((hdr_len = NETSTACK_FRAMER.create()) < 0) {
1134 LOG_ERR(
"! can't send packet due to framer error\n");
1143 LOG_ERR(
"! can't send packet to ");
1144 LOG_ERR_LLADDR(
addr);
1145 LOG_ERR_(
" with seqno %u, queue %u/%u %u/%u\n",
1146 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
1150 ret = MAC_TX_QUEUE_FULL;
1152 p->header_len = hdr_len;
1153 LOG_INFO(
"send packet to ");
1154 LOG_INFO_LLADDR(
addr);
1155 LOG_INFO_(
" with seqno %u, queue %u/%u %u/%u, len %u %u\n",
1156 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
1159 QUEUEBUF_NUM, p->header_len, queuebuf_datalen(p->qb));
1163 mac_call_sent_callback(sent, ptr, ret, 1);
1170 int frame_parsed = 1;
1172 frame_parsed = NETSTACK_FRAMER.parse();
1174 if(frame_parsed < 0) {
1180 if(packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO) != 0xffff) {
1185 LOG_WARN(
"! drop dup ll from ");
1186 LOG_WARN_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
1187 LOG_WARN_(
" seqno %u\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
1194 LOG_INFO(
"received from ");
1195 LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
1196 LOG_INFO_(
" with seqno %u\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
1200 NETSTACK_NETWORK.input();
1208 if(tsch_is_initialized == 1 && tsch_is_started == 0) {
1209 tsch_is_started = 1;
1212 if(TSCH_EB_PERIOD > 0) {
1218 LOG_INFO(
"starting as %s\n", tsch_is_coordinator ?
"coordinator":
"node");
1227 NETSTACK_RADIO.off();
1238 if(!tsch_is_associated) {
1239 LOG_WARN(
"Cannot compute max payload size: not associated\n");
1243 res = NETSTACK_RADIO.get_value(RADIO_CONST_MAX_PAYLOAD_LEN,
1244 &max_radio_payload_len);
1247 LOG_ERR(
"Failed to retrieve max radio driver payload length\n");
1254 framer_hdrlen = NETSTACK_FRAMER.length();
1255 if(framer_hdrlen < 0) {
1260 return MIN(max_radio_payload_len, TSCH_PACKET_MAX_LEN)
1262 - LLSEC802154_PACKETBUF_MIC_LEN();
A MAC framer for IEEE 802.15.4.
clock_time_t clock_time(void)
Get the current clock time.
#define CLOCK_SECOND
A second, measured in system clock time.
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
static void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
void etimer_restart(struct etimer *et)
Restart an event timer from the current point in time.
void etimer_reset(struct etimer *et)
Reset an event timer with the same interval as was previously set.
static bool etimer_expired(struct etimer *et)
Check if an event timer has expired.
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
int frame802154_parse(uint8_t *data, int len, frame802154_t *pf)
Parses an input frame.
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.
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
uint8_t packetbuf_hdrlen(void)
Get the length of the header in the packetbuf.
int packetbuf_copyfrom(const void *from, uint16_t len)
Copy from external data into the packetbuf.
void packetbuf_clear(void)
Clear and reset the packetbuf.
#define PROCESS_WAIT_UNTIL(c)
Wait for a condition to occur.
#define PROCESS(name, strname)
Declare a process.
void process_post_synch(struct process *p, process_event_t ev, process_data_t data)
Post a synchronous event to a process.
#define PROCESS_PT_SPAWN(pt, thread)
Spawn a protothread from the process.
#define PROCESS_BEGIN()
Define the beginning of a process.
#define PROCESS_END()
Define the end of a process.
void process_start(struct process *p, process_data_t data)
Start a process.
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
void process_poll(struct process *p)
Request a process to be polled.
#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_WAIT_UNTIL(pt, condition)
Block and wait until condition is true.
#define RADIO_RX_MODE_POLL_MODE
Enable/disable/get the state of radio driver poll mode operation.
enum radio_result_e radio_result_t
Radio return values when setting or getting radio parameters.
int radio_value_t
Each radio has a set of parameters that designate the current configuration and state of the radio.
@ RADIO_RESULT_NOT_SUPPORTED
The parameter is not supported.
@ RADIO_RESULT_OK
The parameter was set/read successfully.
@ RADIO_PARAM_LAST_PACKET_TIMESTAMP
Last packet timestamp, of type rtimer_clock_t.
@ 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_TX_MODE
Radio transmission mode determines if the radio has send on CCA (RADIO_TX_MODE_SEND_ON_CCA) enabled o...
#define RTIMER_SECOND
Number of rtimer ticks for 1 second.
#define RTIMER_NOW()
Get the current clock time.
static void send_packet(void)
This function is called by the 6lowpan code to send out a packet.
void sixtop_input(void)
Input a packet stored in packetbuf.
void sixtop_init(void)
Initialize 6top module This initialization function removes all the SFs which has been installed into...
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.
void tsch_queue_free_unused_neighbors(void)
Deallocate all neighbors with empty queue.
int tsch_schedule_init(void)
Module initialization, call only once at init.
struct tsch_neighbor * tsch_queue_get_time_source(void)
Get the TSCH time source (we currently assume there is only one)
void tsch_queue_free_packet(struct tsch_packet *p)
Free a packet.
int tsch_packet_parse_eb(const uint8_t *buf, int buf_size, frame802154_t *frame, struct ieee802154_ies *ies, uint8_t *hdr_len, int frame_without_mic)
Parse EB.
void tsch_security_set_packetbuf_attr(uint8_t frame_type)
Set packetbuf (or eackbuf) attributes depending on a given frame type.
struct tsch_link * tsch_schedule_add_link(struct tsch_slotframe *slotframe, uint8_t link_options, enum link_type link_type, const linkaddr_t *address, uint16_t timeslot, uint16_t channel_offset, uint8_t do_remove)
Adds a link to a slotframe.
#define TSCH_ASN_DIVISOR_INIT(div, val_)
Initialize a struct asn_divisor_t.
void tsch_schedule_create_minimal(void)
Create a 6tisch minimal schedule with length TSCH_SCHEDULE_DEFAULT_LENGTH.
#define TSCH_ASN_INIT(asn, ms1b_, ls4b_)
Initialize ASN.
#define TSCH_ASN_DIFF(asn1, asn2)
Returns the 32-bit diff between asn1 and asn2.
int tsch_queue_global_packet_count(void)
Returns the number of packets currently in all TSCH queues.
int tsch_schedule_remove_all_slotframes(void)
Removes all slotframes, resulting in an empty schedule.
int tsch_queue_update_time_source(const linkaddr_t *new_addr)
Update TSCH time source.
struct tsch_packet * tsch_queue_add_packet(const linkaddr_t *addr, uint8_t max_transmissions, mac_callback_t sent, void *ptr)
Add packet to neighbor queue.
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)
void tsch_adaptive_timesync_reset(void)
Reset the status of the module.
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.
void tsch_set_ka_timeout(uint32_t timeout)
Set the desynchronization timeout after which a node sends a unicasst keep-alive (KA) to its time sou...
void tsch_queue_reset(void)
Reset neighbor queues module.
struct tsch_neighbor * tsch_queue_add_nbr(const linkaddr_t *addr)
Add a TSCH neighbor queue.
void tsch_queue_init(void)
Initialize TSCH queue module.
int tsch_packet_create_eb(uint8_t *hdr_len, uint8_t *tsch_sync_ie_offset)
Create an EB packet directly in packetbuf.
void tsch_log_init(void)
Initialize log module.
void tsch_set_eb_period(uint32_t period)
Set the period at wich TSCH enhanced beacons (EBs) are sent.
struct tsch_slotframe * tsch_schedule_add_slotframe(uint16_t handle, uint16_t size)
Creates and adds a new slotframe.
void tsch_set_coordinator(int enable)
Set the node as PAN coordinator.
void tsch_log_process_pending(void)
Process pending log messages.
linkaddr_t * tsch_queue_get_nbr_address(const struct tsch_neighbor *n)
Get the address of a neighbor.
void tsch_set_pan_secured(int enable)
Enable/disable security.
void tsch_set_join_priority(uint8_t jp)
Set the TSCH join priority (JP)
void tsch_disassociate(void)
Leave the TSCH network we are currently in.
void tsch_slot_operation_start(void)
Start actual slot operation.
Header file for the logging system.
void mac_sequence_set_dsn(void)
Sets and increments the destination sequence number.
int mac_sequence_is_duplicate(void)
Tell whether the packetbuf is a duplicate packet.
void mac_sequence_register_seqno(void)
Register the sequence number of the packetbuf.
void mac_sequence_init(void)
brief Initializes the destination sequence number to a random value.
Header file for MAC sequence numbers management.
@ MAC_TX_DEFERRED
The MAC layer transmission could not be performed because of an error.
@ MAC_TX_NOACK
The MAC layer deferred the transmission for a later time.
@ 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)
static void packet_input(void)
Called by the radio driver process when a frame has been received.
Header file for the Packet buffer (packetbuf) management.
Header file for the Packet queue buffer management.
Header file for the radio API.
Header file for generating non-cryptographic random numbers.
int ringbufindex_peek_get(const struct ringbufindex *r)
Return the index of the first element which will be removed if calling ringbufindex_get.
void ringbufindex_init(struct ringbufindex *r, uint8_t size)
Initialize a ring buffer.
int ringbufindex_get(struct ringbufindex *r)
Remove the first element and return its index.
Routing driver header file.
6TiSCH Operation Sublayer (6top) APIs
uint8_t frame_version
2 bit.
uint8_t security_enabled
1 bit.
Parameters used by the frame802154_create() function.
uint8_t src_addr[8]
Source address.
uint16_t src_pid
Source PAN ID.
frame802154_fcf_t fcf
Frame control field
The structure of a MAC protocol driver in Contiki.
int(* on)(void)
Turn the MAC layer on.
int(* max_payload)(void)
Read out estimated max payload size based on payload in packetbuf.
void(* send)(mac_callback_t sent_callback, void *ptr)
Send a packet from the packetbuf
uint8_t(* is_in_leaf_mode)(void)
Tells whether the protocol is in leaf mode.
For quick modulo operation on ASN.
The ASN is an absolute slot number over 5 bytes.
TSCH neighbor information.
802.15.4e slotframe (contains links)
void tsch_roots_set_self_to_root(uint8_t is_root)
Set the root status of the local node.
void tsch_roots_add_address(const linkaddr_t *root_address)
Add address as a potential RPL root that is a single-hop neighbor in the TSCH network.
void tsch_roots_init(void)
Initialize the list of RPL network roots.
Main API declarations for TSCH.
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.