zigbee 52840

I want to know if I call the following function, which condition should I meet to determine that the coordinator is not connected to any terminal devices.  For example, I now think that IF my ZigBee Dongle is not connected to any terminal device, I will take a zigBee Dongle light operation, but now I call the following function and I don't know what conditions are satisfied to achieve this goal.  The "sig" value in this function determines that ZigBee Dongle is not connected to any terminal devices  

Parents Reply Children
  • hi,

    The Zigbee Dongle is connected to multiple terminal devices, which are disconnected from the Zigbee Dongle if they have all gone offline.  How this state is represented in the code, in other words, what function is called in the code under this path to indicate that there is no device connected in "Zigbee Dongle".  

    \examples\zigbee\experimental\cli\cli_agent_router

    My guess is that it has something to do with this function "zb_get_app_signal", but I can't find a definition for this function.  What other function can determine that no devices are connected to the network in ZigBee Dongle  

    thank you.

  • Hello, 

    I've gotten some help from our experts:

    If the Dongle is the coordinator, then there is no zb_zdo_app_signal_type_t signal for this. If the device is a router or end device they should get the signal ZB_NWK_SIGNAL_NO_ACTIVE_LINKS_LEFT when there are no other routers or coordinator in the network, but a router will get this signal even if there are end devices in the network. They can find the signals in external\zboss\include\zboss_api_zdo.h.
    For a coordinator they would have to implement some logic to check whether there are nodes on the network. I am not sure what the best way to do this would be, but I can think of two possible methods. One way is to check the Dongle's neighbor table. They can get the neighbour table using the CLI command "zdo mgmt_lqi 0x0000" or the function zb_zdo_mgmt_lqi_req(). However, the customer should be aware that stale nodes are not automatically removed in the neighbor table, but there are ways to mark them as stale. The following simple snippet can be placed in zigbee_cli_cmd_zdo.c and read the internal neighbor table through 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 (ZC 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]
    If all nodes are stale, then there are no nodes in range of the Dongle anymore.

    The other way is to send a match descriptor request. This finds nodes with specific clusters, and all devices shall have the Basic cluster implemented, so sending a match descriptor request with the Basic cluster should return all devices in the network in range of the Dongle. They can do this by either sending the CLI command "zdo match_desc" with address set to broadcast (0xffff) and cluster 0, or by using the function zb_zdo_match_desc_req().

    An application signal is described with the following parameters:

    To get the signal description, the application calls zb_get_app_signal(). For example:

    zb_zdo_app_signal_t zb_get_app_signal(zb_uint8_t param, zb_zdo_app_signal_hdr_t **p_sg_p);

    Where:

    • param is the reference to a memory buffer,
    • ev_p is the pointer to store the extended event info; can be NULL. The function returns an ID of the application signal.
    Have a look into the signal id zb_zdo_app_signal_t for an overview of signal types:
    Kind regards,
    Øyvind
  • hi,

    I probably understand what you mean. If my Dongle is ZC, there is no API in the code that can represent the state of all devices being off the network. Can we write this API ourselves?  I was hoping you could help me  

  • hi,

    I hope to get your reply as soon as possible. Based on this problem, if there is no zb_zdo_app_signal_type_t signal, I hope you can add this missing API for our subsequent development  

  • My apologies, I was out of office last week. 

    The nRF5 SDK does not have this and users are expected to implement this themselves. Our expert respondes:

    The neighbors of the device are stored in a neighbor table, gc_neighbor. By iterating through this table you get all of the device's neighbors. If the device does not have any neighbors in the neighbor table, then there are no other devices on the network that are in range of the device. If it has neighbors, but their state is stale, then they were on the network and in range, but are not anymore.
    This is very simple and may not be exactly what you want, but it shows how to use the neighbor table to see if there are other devices on the network (in range of the device), and they can use this as a starting point.
    Calling this function will simply print the entries in the neighbor table.
    For end devices you have something called end device timeout. This is something the end device itself sets (with zb_set_ed_timeout in nRF5 SDK), and the end device informs its parent of this timeout, such that the parent will delete the child entry from the neighbor table if the end device has not communicated with the parent in the amount of time specified by the end device timeout. When it has timed out, the end device will be removed from the neighbor table.
    Routers and coordinators are not removed from the neighbor table, but you can find that the entry is stale by looking at the outgoing cost of the entry in the neighbor table. Normally, the cost of an outgoing link is 1-7. However, if a neighbor entry is considered stale, then this cost will be set to 0. Since the entries are not removed, you will have to handle stale entries in some way.
    /* Get neighbor table */
    static zb_void_t get_neighbors()
    {
        uint32_t i;
        zb_uint16_t addr;
        for (i = 0; i < gc_neighbor_table_size; i++)
        {
            /* If gc_neighbor[i].used is 0, the entry is not used */
            /* If gc_neighbor[i].ext_neighbor is 1, this is ext neighbor record, else base neighbor */
            if ((gc_neighbor[i].used == 0) ||
                (gc_neighbor[i].ext_neighbor != 0))
            {
                continue;
            }
            
            zb_address_short_by_ref(&addr, gc_neighbor[i].u.base.addr_ref);
            NRF_LOG_INFO("short_addr: 0x%04x", addr);
            switch (gc_neighbor[i].device_type) {
                case ZB_NWK_DEVICE_TYPE_COORDINATOR:
                    NRF_LOG_INFO("device type: ZC ");
                    break;
     
                case ZB_NWK_DEVICE_TYPE_ROUTER:
                    NRF_LOG_INFO("device type: ZR  ");
                    break;
     
                case ZB_NWK_DEVICE_TYPE_ED:
                    NRF_LOG_INFO("device type: ZED ");
                    break;
     
                default:
                    NRF_LOG_INFO("device type: ??? ");
                    break;
            }
            if (gc_neighbor[i].device_type != ZB_NWK_DEVICE_TYPE_ED)
            {
                /* The number of nwkLinkStatusPeriod intervals since a link status command was received */
                NRF_LOG_INFO("age: %03u ", gc_neighbor[i].u.base.age);
            }
            else
            {
                /* Time left of ED timeout */
                zb_time_t exp_time = ZB_TIME_SUBTRACT(gc_neighbor[i].u.base.time_to_expire, ZB_TIMER_GET());
                NRF_LOG_INFO("timeout: %07u", ZB_TIME_BEACON_INTERVAL_TO_MSEC(exp_time) / 1000);
            }
            if ((gc_neighbor[i].device_type != ZB_NWK_DEVICE_TYPE_ED) &&
                (gc_neighbor[i].u.base.outgoing_cost == 0))
            {   /* Outgoing cost of router or coordinator neighbor entry being 0 means the entry is stale */
                NRF_LOG_INFO("[STALE]");
            }
        }
    }
    Kind regards,
    Øyvind
Related