53#include "net/nbr-table.h"
54#include "net/link-stats.h"
58#include "lib/random.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");
161static void packet_input(
void);
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)
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()) {
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) {
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)
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();
1004 if(TSCH_DEFAULT_TIMESLOT_TIMING == NULL) {
1005 LOG_ERR(
"! platform does not provide a timeslot timing template.\n");
1010 if(NETSTACK_RADIO.get_value(RADIO_CONST_MAX_PAYLOAD_LEN, &radio_max_payload_len) !=
RADIO_RESULT_OK) {
1011 LOG_ERR(
"! radio does not support getting RADIO_CONST_MAX_PAYLOAD_LEN. Abort init.\n");
1017 LOG_ERR(
"! radio does not support getting RADIO_PARAM_RX_MODE. Abort init.\n");
1021 radio_rx_mode &= ~RADIO_RX_MODE_ADDRESS_FILTER;
1023 radio_rx_mode &= ~RADIO_RX_MODE_AUTOACK;
1027 LOG_ERR(
"! radio does not support setting required RADIO_PARAM_RX_MODE. Abort init.\n");
1033 LOG_ERR(
"! radio does not support getting RADIO_PARAM_TX_MODE. Abort init.\n");
1037 radio_tx_mode &= ~RADIO_TX_MODE_SEND_ON_CCA;
1039 LOG_ERR(
"! radio does not support setting required RADIO_PARAM_TX_MODE. Abort init.\n");
1044 LOG_ERR(
"! radio does not support setting channel. Abort init.\n");
1049 LOG_ERR(
"! radio does not support getting last packet timestamp. Abort init.\n");
1053 if(TSCH_HOPPING_SEQUENCE_MAX_LEN <
sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE)) {
1054 LOG_ERR(
"! TSCH_HOPPING_SEQUENCE_MAX_LEN < sizeof(TSCH_DEFAULT_HOPPING_SEQUENCE). Abort init.\n");
1059#if TSCH_AUTOSELECT_TIME_SOURCE
1060 nbr_table_register(eb_stats, NULL);
1070 tsch_is_initialized = 1;
1092 const linkaddr_t *
addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
1093 uint8_t max_transmissions = 0;
1095 if(!tsch_is_associated) {
1096 if(!tsch_is_initialized) {
1097 LOG_WARN(
"! not initialized (see earlier logs), drop outgoing packet\n");
1099 LOG_WARN(
"! not associated, drop outgoing packet\n");
1102 mac_call_sent_callback(sent, ptr, ret, 1);
1109 packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
1114 addr = &tsch_broadcast_address;
1117 packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME);
1119#if LLSEC802154_ENABLED
1125 max_transmissions = packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS);
1126 if(max_transmissions == 0) {
1128 max_transmissions = TSCH_MAC_MAX_FRAME_RETRIES + 1;
1131 if((hdr_len = NETSTACK_FRAMER.create()) < 0) {
1132 LOG_ERR(
"! can't send packet due to framer error\n");
1141 LOG_ERR(
"! can't send packet to ");
1142 LOG_ERR_LLADDR(
addr);
1143 LOG_ERR_(
" with seqno %u, queue %u/%u %u/%u\n",
1144 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
1148 ret = MAC_TX_QUEUE_FULL;
1150 p->header_len = hdr_len;
1151 LOG_INFO(
"send packet to ");
1152 LOG_INFO_LLADDR(
addr);
1153 LOG_INFO_(
" with seqno %u, queue %u/%u %u/%u, len %u %u\n",
1154 packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO),
1157 QUEUEBUF_NUM, p->header_len, queuebuf_datalen(p->qb));
1161 mac_call_sent_callback(sent, ptr, ret, 1);
1168 int frame_parsed = 1;
1170 frame_parsed = NETSTACK_FRAMER.parse();
1172 if(frame_parsed < 0) {
1178 if(packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO) != 0xffff) {
1183 LOG_WARN(
"! drop dup ll from ");
1184 LOG_WARN_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
1185 LOG_WARN_(
" seqno %u\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
1192 LOG_INFO(
"received from ");
1193 LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER));
1194 LOG_INFO_(
" with seqno %u\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
1198 NETSTACK_NETWORK.input();
1206 if(tsch_is_initialized == 1 && tsch_is_started == 0) {
1207 tsch_is_started = 1;
1210 if(TSCH_EB_PERIOD > 0) {
1216 LOG_INFO(
"starting as %s\n", tsch_is_coordinator ?
"coordinator":
"node");
1225 NETSTACK_RADIO.off();
1236 if(!tsch_is_associated) {
1237 LOG_WARN(
"Cannot compute max payload size: not associated\n");
1241 res = NETSTACK_RADIO.get_value(RADIO_CONST_MAX_PAYLOAD_LEN,
1242 &max_radio_payload_len);
1245 LOG_ERR(
"Failed to retrieve max radio driver payload length\n");
1252 framer_hdrlen = NETSTACK_FRAMER.length();
1253 if(framer_hdrlen < 0) {
1258 return MIN(max_radio_payload_len, TSCH_PACKET_MAX_LEN)
1260 - LLSEC802154_PACKETBUF_MIC_LEN();
A MAC framer for IEEE 802.15.4.
clock_time_t clock_time(void)
Get the current clock time.
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
#define CLOCK_SECOND
A second, measured in system clock time.
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
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.
int 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_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_THREAD(name_args)
Declaration of a protothread.
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
#define PT_WAIT_UNTIL(pt, condition)
Block and wait until condition is true.
#define PT_END(pt)
Declare the end of a protothread.
#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_BUSYWAIT_UNTIL_ABS(cond, t0, max_time)
Busy-wait until a condition.
#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)
Header file for the Packet buffer (packetbuf) management.
Header file for the Packet queue buffer management.
Header file for the radio API.
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.