This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

NRF52840 zigbee router's neighbour table (management lqi) is not updating even if the end device is disconnected

I have created zigbee network using nordic dk board, i am trying to fetch all the active nodes in the network using zdo mgmt_lqi cli and i am getting those details but when i power off any device and then if i fetch the neighbour table i am getting that powered off device too. I have tried to fetch even after 15 minutes but still i am getting that device.

Is there any timeout is defined for this ? or how can i update this neighbour table details?

Parents Reply
  • Hi,

    I have a few updates from the Zigbee team, which I copied here:

    • There is no public API to get the "stale"status from the neighbor table. You can try to use the dynamic memory configuration feature, that will move the table from the stack to the application memory and include definitions from zboss_api_internal.h to iterate through it, but this is rather a hack than a solution.
    • Unfortunately we were unable to find clear statements inside the Zigbee specification, whether stale entries should or should not be included in the MGMT LQI Response. That said, it seems to be valid to include them. Unfortunately - this prevents you from using this responses as the input for applications such as Zigbee topology monitors.
    • As a potential, future solution, I have asked if it would be valid to change the LQI values to something very low, if the device is marked as stale. Again - I was not able to find something inside the specification, that will require this change inside the stack, but I do see a value in having some sort of indication for external nodes, that the entry has been marked as stale, that's why I proposed it. It has not been decided yet, if it will happen - currently it is being discussed.

    Best regards,

    Marte

Children
  • Thanks for the update.

    Can you please explain 1st point, because what I understood from this point is that I can move neighbor table from stack to memory, and then I have to fetch "outgoing_cost" for every node?

  • Hi,

    They were referring to the software/protocol stack instead of the hardware/memory region.

    To have created a code snippet that you can plug into the zigbee_cli_cmd_zdo.c file, to make things clearer. Afterwards you can read the internal neighbor table through the zdo neighbors command:

    /**
     * @brief Prints all entries of the neighbor table.
     *
     * @code
     * zdo neighbors
     * @endcode
     *
     * Example:
     * @code
     * zdo neighbors
     * @endcode
     */
    static void cmd_zb_neighbors(nrf_cli_t const * p_cli, size_t argc, char **argv)
    {
        uint32_t i;
        zb_ieee_addr_t ieee_addr;
        zb_uint16_t addr;
     
        if ((argc > 1) || (nrf_cli_help_requested(p_cli)))
        {
            print_usage(p_cli, argv[0], "");
            return;
        }
     
        nrf_cli_fprintf(p_cli,
                        NRF_CLI_NORMAL,
                        "\r\n[idx] "
                        "ext_addr         "
                        "short_addr "
                        "type "
                        "sleepy "
                        "lqi "
                        "age "
                        "timeout "
                        "relationship\r\n");
     
        for (i = 0; i < gc_neighbor_table_size; i++)
        {
            if ((gc_neighbor[i].used == 0) ||
                (gc_neighbor[i].ext_neighbor != 0))
            {
                continue;
            }
     
            nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "[%3u] ", i);
     
            zb_address_ieee_by_ref(ieee_addr, gc_neighbor[i].u.base.addr_ref);
            print_eui64(p_cli, ieee_addr);
     
            zb_address_short_by_ref(&addr, gc_neighbor[i].u.base.addr_ref);
            nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " 0x%04x    ", addr);
     
            switch (gc_neighbor[i].device_type) {
                case ZB_NWK_DEVICE_TYPE_COORDINATOR:
                    nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " ZC  ");
                    break;
     
                case ZB_NWK_DEVICE_TYPE_ROUTER:
                    nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " ZR  ");
                    break;
     
                case ZB_NWK_DEVICE_TYPE_ED:
                    nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " ZED ");
                    break;
     
                default:
                    nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " ??? ");
                    break;
            }
     
            if (gc_neighbor[i].rx_on_when_idle)
            {
                nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " false ");
            }
            else
            {
                nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " true  ");
            }
     
            nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " %03u", gc_neighbor[i].lqi);
     
            if (gc_neighbor[i].device_type != ZB_NWK_DEVICE_TYPE_ED)
            {
                nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " %03u  ---   ", gc_neighbor[i].u.base.age);
            }
            else
            {
                zb_time_t exp_time = ZB_TIME_SUBTRACT(gc_neighbor[i].u.base.time_to_expire, ZB_TIMER_GET());
                nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " --- %07u", ZB_TIME_BEACON_INTERVAL_TO_MSEC(exp_time) / 1000);
            }
     
            switch (gc_neighbor[i].relationship) {
                case 0x00:
                    nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " parent");
                    break;
     
                case 0x01:
                    nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " child");
                    break;
     
                case 0x02:
                    nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " sibling");
                    break;
     
                case 0x03:
                    nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " none");
                    break;
     
                case 0x04:
                    nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " previous child");
                    break;
     
                case 0x05:
                    nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " unauthenticated child");
                    break;
     
                default:
                    nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " unknown");
                    break;
            }
     
            if ((gc_neighbor[i].device_type != ZB_NWK_DEVICE_TYPE_ED) &&
                (gc_neighbor[i].u.base.outgoing_cost == 0))
            {
                nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, " [STALE]\r\n");
            }
            else
            {
                nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\r\n");
            }
        }
     
        print_done(p_cli, ZB_TRUE);
    }
    ...
        NRF_CLI_CMD(neighbors, NULL, "lists all entries from the neighbor table", cmd_zb_neighbors),
        NRF_CLI_SUBCMD_SET_END
    };

    Example output for an aged-out router (Zigbee coordinator in this case):

    > zdo neighbors


    [idx] ext_addr short_addr type sleepy lqi age timeout relationship

    [ 0] f4ce36aaaaaaaaaa 0x0000 ZC false 255 003 --- parent [STALE]

    They also tested end device aging. The entry for the end device was simply removed after the timeout.

    Best regards,

    Marte

  • Thanks for the function.

    I have used as you mentioned and it is working as you told, so I am getting stale entry but can I delete that node from the stack so neighbor table will get that update?

    If above is not possible then when I'll got any stale entry then in order to update neighbor table should that node has to leave and then re-connect the network?

  • Hi,

    I am not aware of any functions available to the user that delete stale nodes. In the case of end device keep alive, this happens as part of the stack when an end device, using end device keep alive, timeouts, resulting in the parent deleting it.

    However, you can try sending a mgmt_leave_req command. This command is used by a local device to request another device to leave the network. I do not know how this will work with a device that has already left, as the device that is requested to leave is supposed to process the request and report back to the local device via the mgmt_leave_rsp command. The easiest way to test this would be to use CLI and send the command zdo mgmt_leave:

    zdo mgmt_leave <h:16-bit dst_addr> [h:device_address eui64] [--children] [--rejoin]

    You can see examples of how this command is used in the CLI example here. You can also find more information about the mgmt_leave_req command in the Zigbee specification (chapter 2.4.3.3.5 in revision 21 found here), and the zb_zdo_mgmt_leave_req_s struct reference.

    I have not tested the mgmt_leave_req command in the case of a stale node myself, so I can not guarantee that it will work. Please let me know if it does not, and I will see if I can find other solutions for this.

    As far as I know, it is not possible to force the device to update its neighbor table or routes, so the solution might be to leave and reconnect as you said. If the above solution does not work, I will ask about this internally.

    Best regards,

    Marte

  • I have already tried zdo mgmt_leave command, this command is not working on node which has already left the network, getting response timeout error.

Related