/* A periodic process to send TSCH Enhanced Beacons (EB) */ PROCESS_THREAD(tsch_send_eb_process, ev, data) { static struct etimer eb_timer; PROCESS_BEGIN(); /* Wait until association */ etimer_set(&eb_timer, CLOCK_SECOND / 10); while(!tsch_is_associated) { PROCESS_WAIT_UNTIL(etimer_expired(&eb_timer)); etimer_reset(&eb_timer); } /* Set an initial delay except for coordinator, which should send an EB asap */ if(!tsch_is_coordinator) { etimer_set(&eb_timer, random_rand() % TSCH_EB_PERIOD); PROCESS_WAIT_UNTIL(etimer_expired(&eb_timer)); } while(1) { unsigned long delay; if(tsch_is_associated && tsch_current_eb_period > 0) { /* Enqueue EB only if there isn't already one in queue */ if(tsch_queue_packet_count(&tsch_eb_address) == 0) { int eb_len; uint8_t hdr_len = 0; uint8_t tsch_sync_ie_offset; /* Prepare the EB packet and schedule it to be sent */ eb_len = tsch_packet_create_eb(&hdr_len, &tsch_sync_ie_offset); if(eb_len > 0) { struct tsch_packet *p; /* Enqueue EB packet */ if(!(p = tsch_queue_add_packet(&tsch_eb_address, NULL, NULL))) { PRINTF("TSCH:! could not enqueue EB packet\n"); } else { PRINTF("TSCH: enqueue EB packet %u %u\n", eb_len, hdr_len); p->tsch_sync_ie_offset = tsch_sync_ie_offset; p->header_len = hdr_len; } } } } if(tsch_current_eb_period > 0) { /* Next EB transmission with a random delay * within [tsch_current_eb_period*0.75, tsch_current_eb_period[ */ delay = (tsch_current_eb_period - tsch_current_eb_period / 4) + random_rand() % (tsch_current_eb_period / 4); } else { delay = TSCH_EB_PERIOD; } etimer_set(&eb_timer, delay); PROCESS_WAIT_UNTIL(etimer_expired(&eb_timer)); } PROCESS_END(); }
/* Function send for TSCH-MAC, puts the packet in packetbuf in the MAC queue */ static void send_packet(mac_callback_t sent, void *ptr) { int ret = MAC_TX_DEFERRED; int packet_count_before; int hdr_len = 0; const linkaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER); if(!tsch_is_associated) { if(!tsch_is_initialized) { PRINTF("TSCH:! not initialized (see earlier logs), drop outgoing packet\n"); } else { PRINTF("TSCH:! not associated, drop outgoing packet\n"); } ret = MAC_TX_ERR; mac_call_sent_callback(sent, ptr, ret, 1); return; } /* PACKETBUF_ATTR_MAC_SEQNO cannot be zero, due to a pecuilarity in framer-802154.c. */ if(++tsch_packet_seqno == 0) { tsch_packet_seqno++; } /* Ask for ACK if we are sending anything other than broadcast */ if(!linkaddr_cmp(addr, &linkaddr_null)) { packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1); } else { /* Broadcast packets shall be added to broadcast queue * The broadcast address in Contiki is linkaddr_null which is equal * to tsch_eb_address */ addr = &tsch_broadcast_address; } packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME); packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, tsch_packet_seqno); #if TSCH_SECURITY_ENABLED if(tsch_is_pan_secured) { /* Set security level, key id and index */ packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, TSCH_SECURITY_KEY_SEC_LEVEL_OTHER); packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, FRAME802154_1_BYTE_KEY_ID_MODE); /* Use 1-byte key index */ packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, TSCH_SECURITY_KEY_INDEX_OTHER); } #endif /* TSCH_SECURITY_ENABLED */ packet_count_before = tsch_queue_packet_count(addr); if((hdr_len = NETSTACK_FRAMER.create()) < 0) { PRINTF("TSCH:! can't send packet due to framer error\n"); ret = MAC_TX_ERR; } else { struct tsch_packet *p; /* Enqueue packet */ p = tsch_queue_add_packet(addr, sent, ptr); if(p == NULL) { PRINTF("TSCH:! can't send packet !tsch_queue_add_packet\n"); ret = MAC_TX_ERR; } else { p->header_len = hdr_len; PRINTF("TSCH: send packet to %u with seqno %u, queue %u %u, len %u %u\n", TSCH_LOG_ID_FROM_LINKADDR(addr), tsch_packet_seqno, packet_count_before, tsch_queue_packet_count(addr), p->header_len, queuebuf_datalen(p->qb)); } } if(ret != MAC_TX_DEFERRED) { mac_call_sent_callback(sent, ptr, ret, 1); } }
/* A periodic process to send TSCH Enhanced Beacons (EB) */ PROCESS_THREAD(tsch_send_eb_process, ev, data) { static struct etimer eb_timer; PROCESS_BEGIN(); /* Wait until association */ etimer_set(&eb_timer, CLOCK_SECOND / 10); while(!tsch_is_associated) { PROCESS_WAIT_UNTIL(etimer_expired(&eb_timer)); etimer_reset(&eb_timer); } /* Set an initial delay except for coordinator, which should send an EB asap */ if(!tsch_is_coordinator) { etimer_set(&eb_timer, random_rand() % TSCH_EB_PERIOD); PROCESS_WAIT_UNTIL(etimer_expired(&eb_timer)); } while(1) { unsigned long delay; if(tsch_is_associated && tsch_current_eb_period > 0) { /* Enqueue EB only if there isn't already one in queue */ if(tsch_queue_packet_count(&tsch_eb_address) == 0) { int eb_len; uint8_t hdr_len = 0; uint8_t tsch_sync_ie_offset; /* Prepare the EB packet and schedule it to be sent */ packetbuf_clear(); /* We don't use seqno 0 */ if(++tsch_packet_seqno == 0) { tsch_packet_seqno++; } packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_BEACONFRAME); packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, tsch_packet_seqno); #if TSCH_SECURITY_ENABLED if(tsch_is_pan_secured) { /* Set security level, key id and index */ packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, TSCH_SECURITY_KEY_SEC_LEVEL_EB); packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, FRAME802154_1_BYTE_KEY_ID_MODE); /* Use 1-byte key index */ packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, TSCH_SECURITY_KEY_INDEX_EB); } #endif /* TSCH_SECURITY_ENABLED */ eb_len = tsch_packet_create_eb(packetbuf_dataptr(), PACKETBUF_SIZE, tsch_packet_seqno, &hdr_len, &tsch_sync_ie_offset); if(eb_len != 0) { struct tsch_packet *p; packetbuf_set_datalen(eb_len); /* Enqueue EB packet */ if(!(p = tsch_queue_add_packet(&tsch_eb_address, NULL, NULL))) { PRINTF("TSCH:! could not enqueue EB packet\n"); } else { PRINTF("TSCH: enqueue EB packet %u %u\n", eb_len, hdr_len); p->tsch_sync_ie_offset = tsch_sync_ie_offset; p->header_len = hdr_len; } } } } if(tsch_current_eb_period > 0) { /* Next EB transmission with a random delay * within [tsch_current_eb_period*0.75, tsch_current_eb_period[ */ delay = (tsch_current_eb_period - tsch_current_eb_period / 4) + random_rand() % (tsch_current_eb_period / 4); } else { delay = TSCH_EB_PERIOD; } etimer_set(&eb_timer, delay); PROCESS_WAIT_UNTIL(etimer_expired(&eb_timer)); } PROCESS_END(); }
/* Function send for TSCH-MAC, puts the packet in packetbuf in the MAC queue */ static void send_packet(mac_callback_t sent, void *ptr) { int ret = MAC_TX_DEFERRED; int packet_count_before; int hdr_len = 0; const linkaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER); if(!tsch_is_associated) { if(!tsch_is_initialized) { PRINTF("TSCH:! not initialized (see earlier logs), drop outgoing packet\n"); } else { PRINTF("TSCH:! not associated, drop outgoing packet\n"); } ret = MAC_TX_ERR; mac_call_sent_callback(sent, ptr, ret, 1); return; } /* Ask for ACK if we are sending anything other than broadcast */ if(!linkaddr_cmp(addr, &linkaddr_null)) { packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1); } else { /* Broadcast packets shall be added to broadcast queue * The broadcast address in Contiki is linkaddr_null which is equal * to tsch_eb_address */ addr = &tsch_broadcast_address; } packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME); #if LLSEC802154_ENABLED if(tsch_is_pan_secured) { /* Set security level, key id and index */ packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, TSCH_SECURITY_KEY_SEC_LEVEL_OTHER); packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, FRAME802154_1_BYTE_KEY_ID_MODE); /* Use 1-byte key index */ packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, TSCH_SECURITY_KEY_INDEX_OTHER); } #endif /* LLSEC802154_ENABLED */ packet_count_before = tsch_queue_packet_count(addr); #if !NETSTACK_CONF_BRIDGE_MODE /* * In the Contiki stack, the source address of a frame is set at the RDC * layer. Since TSCH doesn't use any RDC protocol and bypasses the layer to * transmit a frame, it should set the source address by itself. */ packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); #endif if((hdr_len = NETSTACK_FRAMER.create()) < 0) { PRINTF("TSCH:! can't send packet due to framer error\n"); ret = MAC_TX_ERR; } else { struct tsch_packet *p; /* Enqueue packet */ p = tsch_queue_add_packet(addr, sent, ptr); if(p == NULL) { PRINTF("TSCH:! can't send packet to %u with seqno %u, queue %u %u\n", TSCH_LOG_ID_FROM_LINKADDR(addr), packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO), packet_count_before, tsch_queue_packet_count(addr)); ret = MAC_TX_ERR; } else { p->header_len = hdr_len; PRINTF("TSCH: send packet to %u with seqno %u, queue %u %u, len %u %u\n", TSCH_LOG_ID_FROM_LINKADDR(addr), packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO), packet_count_before, tsch_queue_packet_count(addr), p->header_len, queuebuf_datalen(p->qb)); (void)packet_count_before; /* Discard "variable set but unused" warning in case of TSCH_LOG_LEVEL of 0 */ } } if(ret != MAC_TX_DEFERRED) { mac_call_sent_callback(sent, ptr, ret, 1); } }