contiki-ng: Problem with tsch_link: the first KA packet after association will never be sent if given true mac address to tsch_schedule_add_link()
When I was writing my own TSCH scheduler, I set the address parameter in the tsch_schedule_add_link() function to the real MAC address of the neighbor instead of using a tsch_broadcast_address like in orchestra. Because I wanted the unicast link to be dedicated. So the code is like:
// in tsch-schedule.[hc]
/* Adds a link to a slotframe, return a pointer to it (NULL if failure) */
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)
// my schedule plan
static void new_time_source(old, new) // this is called by the call back: TSCH_CALLBACK_NEW_TIME_SOURCE()
{
...
tsch_schedule_add_link(sf_unicast, LINK_OPTION_TX, LINK_TYPE_NORMAL, new_addr,
timeslot_tx, channel_offset, 0);
tsch_schedule_add_link(sf_unicast, LINK_OPTION_RX, LINK_TYPE_NORMAL, new_addr,
timeslot_rx, channel_offset, 0);
...
}
The new_time_source() function is called immediately after receiving EB from the time source. Therefore, before the parent knows this node, the links are already added. In the tsch_schedule_add_link() function, there is a tx_links_count attribute increasing:
if(l->link_options & LINK_OPTION_TX) {
n = tsch_queue_add_nbr(&l->addr);
/* We have a tx link to this neighbor, update counters */
if(n != NULL) {
n->tx_links_count++;
if(!(l->link_options & LINK_OPTION_SHARED)) {
n->dedicated_tx_links_count++;
}
}
}
Since the real MAC address is put to l->addr, n will be a real neighbor (coordinator for this case). Then the tx_links_count increases and is no longer 0. This causes the KA packet from the node never to be sent. And the reason is follows.
- The default common rule will select the KA packet, of course.
- When the default common link is active, it gets a packet and a neighbor in
tsch_slot_operation, it goes
/* Protothread for slot operation, called from rtimer interrupt
* and scheduled from tsch_schedule_slot_operation */
static
PT_THREAD(tsch_slot_operation(struct rtimer *t, void *ptr))
{
....
current_packet = get_packet_and_neighbor_for_link(current_link, ¤t_neighbor);
....
}
- For the KA packet, the
get_packet_and_neighbor_for_link()function finally falls into the case to pick any unicast packet intsch_queue_get_unicast_packet_for_any() - In
tsch_queue_get_unicast_packet_for_any(), it goes
/* Returns the head packet of any neighbor queue with zero backoff counter.
* Writes pointer to the neighbor in *n */
struct tsch_packet *
tsch_queue_get_unicast_packet_for_any(struct tsch_neighbor **n, struct tsch_link *link)
{
if(!tsch_is_locked()) {
struct tsch_neighbor *curr_nbr = (struct tsch_neighbor *)nbr_table_head(tsch_neighbors);
struct tsch_packet *p = NULL;
while(curr_nbr != NULL) {
if(!curr_nbr->is_broadcast && curr_nbr->tx_links_count == 0) {
/* Only look up for non-broadcast neighbors we do not have a tx link to */
p = tsch_queue_get_packet_for_nbr(curr_nbr, link);
if(p != NULL) {
if(n != NULL) {
*n = curr_nbr;
}
return p;
}
}
curr_nbr = (struct tsch_neighbor *)nbr_table_next(tsch_neighbors, curr_nbr);
}
}
return NULL;
}
So eventually, the condition curr_nbr->tx_links_count == 0 stops the KA packet to be selected since tx_links_count is not zero for the tsch_neighbor as mentioned above.
In my experiments, the KA packets are enqueued one after another, but can never be actually sent🤕.
I hope that I’ve explained myself well. And I wonder if it is my wrong usage or a problem in the current implementation?
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 17 (10 by maintainers)
Thank you guys very much for helping me to fix this. Now I have changed the condition code as you said and it works pretty well.😄