NRF52840 Zigbee CLI example but in code

Hello,

I am trying to configure a Zigbee coordinator as done in the CLI example (for example 'bdb role zc' and 'bdb start') to get data from the multi sensor example, but instead of doing this over the CLI, I am trying to achieve this in the code itself. I am quite lost on where to look for the API calls that the CLI interacts with. Could you guide me to the right documentation?

Thanks,

Sebastiaan

Parents
  • Hi Sebastiaan,

    Could you please specify what functionality you want?

    You can find the implementation of CLI commands in the files located in <SDK_ROOT>/components/zigbee/cli. The commands you mention can be found in zigbee_cli_cmd_bdb.c, for example the function cmd_zb_start() for the 'bdb start' command. You will see in the functions that the CLI library does a lot of additional things and checks which are not needed if you are to use the Zigbee functionality directly.

    If you want to implement coordinator functionality you can look at the Zigbee Light Coordinator from the Light Control example, which can be found in <SDK_ROOT>/examples/zigbee/light_control/light_coordinator. This is a simple coordinator with no additional functionality other than being a Zigbee coordinator.

    To set the coordinator role use the following:

    zb_set_network_coordinator_role(IEEE_CHANNEL_MASK);

    For the coordinator you must also set maximum children. This can for example be set to 10:

    zb_set_max_children(MAX_CHILDREN);

    To start the stack ('bdb start') you must use one of the zboss start functions, either zboss_start() or zboss_start_no_autostart(), depending on whether you want to initialize the radio and start commissioning, or if you want to delay commissioning.

    Best regards,

    Marte

  • Hello Marte, thanks for your reply!

    I am just trying to execute the CLI logic but in code

    So I want to have a coordinator that scans the devices in the network (from the multi sensor example the temperature and pressure sensors).

    I want to then bind and subscribe on those as done in the CLI example. Finally, I would like to print out the values received.

    Thanks,

    Sebastiaan 

  • Hi Sebastiaan,

    You should use ZB_BIND_DST_ADDR_MODE_64_BIT_EXTENDED as destination address mode for the bind request. Additionally, source endpoint and source address should be that of the multi sensor, and not of the coordinator.

    You should not hardcode in the short address of the device, as this address is not static and will change if the network data on the device is erased. This is what you should use the match descriptor for, as the match descriptor will give you the short address and endpoint of the device. Please see the light switch example to see how to use the match descriptor request for this.

    Hardcoding the long addresses will work in this case, as they will not changed, but it is not recommended. A device can get it's own long address with the function zb_osif_get_ieee_eui64():

    zb_ieee_addr_t ieee_addr;
    zb_osif_get_ieee_eui64(ieee_addr);

    Getting another device's long address is a bit more work, but if you have the short address, which you should have from the match descriptor request in this case, you can get it by sending a an IEEE_addr_req with zb_zdo_ieee_addr_req(). In the case of the light switch example where the light bulb short address is m_device_ctx.bulb_params.short_addr you can get the long address with the following code:

    /**@brief A callback called on EUI64 address response.
     *
     * @param[in] bufid Reference number to ZBOSS memory buffer.
     */
    static zb_void_t zb_resolve_ieee_addr_cb(zb_bufid_t bufid)
    {
        zb_zdo_ieee_addr_resp_t * p_resp = (zb_zdo_ieee_addr_resp_t *)zb_buf_begin(bufid);
        zb_char_t addr_buf[2 * 8 + 1];    /* 8 bytes (2 characters) plus one byte for null-terminator. */
    
        if (p_resp->status == ZB_ZDP_STATUS_SUCCESS)
        {
            ZB_LETOH64(m_device_ctx.bulb_params.nwk_addr.addr_long, p_resp->ieee_addr_remote_dev);
            UNUSED_RETURN_VALUE(ieee_addr_to_str(addr_buf, sizeof(addr_buf), m_device_ctx.bulb_params.nwk_addr.addr_long));
            NRF_LOG_INFO("Received EUI64 address for device 0x%04x -> %s.", m_device_ctx.bulb_params.short_addr, NRF_LOG_PUSH(addr_buf));
    
        }
        else
        {
            NRF_LOG_WARNING("Unable to resolve EUI64 source address. Status: %d\r\n",
                            p_resp->status);
        }
    
        zb_buf_free(bufid);
    }
    
    
    /**@brief Resolve EUI64 by sending IEEE address request.
     *
     * @param[in] bufid     Reference number to ZBOSS memory buffer.
     * @param[in] nwk_addr  Network address to be resolved.
     */
    static zb_void_t zb_resolve_ieee_addr()
    {
        zb_zdo_ieee_addr_req_param_t * p_req = NULL;
        zb_uint8_t                     tsn = 0;
        zb_bufid_t                     bufid;
        bufid = zb_buf_get_out();
    
        // Create new IEEE address request and fill with default values.
        p_req = ZB_BUF_GET_PARAM(bufid, zb_zdo_ieee_addr_req_param_t);
        p_req->start_index  = 0;
        p_req->request_type = 0;
        p_req->nwk_addr     = m_device_ctx.bulb_params.short_addr;
        p_req->dst_addr     = p_req->nwk_addr;
        tsn = zb_zdo_ieee_addr_req(bufid, zb_resolve_ieee_addr_cb);
        if (tsn == ZB_ZDO_INVALID_TSN)
        {
            NRF_LOG_WARNING("Failed to send IEEE address request for address: 0x%04x", m_device_ctx.bulb_params.short_addr);
            zb_buf_free(bufid);
        }
    }

    Note that here I have added zb_addr_u nwk_addr to light_switch_sensor_params_t and is using that to store the long address of the light bulb.

    Best regards,

    Marte

  • Hi Marte,

    thanks for the explanation!

    I have a few questions:

    regarding your comment "Additionally, source endpoint and source address should be that of the multi sensor, and not of the coordinator."

    I think I implemented it correctly unless I misunderstood this comment?

    regarding the byte order of the 64-bit addresses in the memory:

    My initial thought (hardcoding) was that if my address was "0xf4ce36f7a5db776c", that 

    p_req->src_address[0] = 0xF4;
    ...
    p_req->src_address[7] = 0x6C;

    However, I see now that with the function below:

    zb_ieee_addr_t ieee_addr;
    zb_osif_get_ieee_eui64(ieee_addr);

    The byte order is

     

    p_req->src_address[0] = 0x6C;
    ...
    p_req->src_address[7] = 0xF4;

    Which one is the correct implementation?

    Thanks a lot for your help so far

    Sebastiaan

  • Hi Sebastiaan,

    The second byte order, starting with 0x6C and ending with 0xF4, is the correct one. The nRF 802.15.4 radio driver use little-endian for addresses, so the address should start with the least-significant byte. 

    Do you still get "Uninplemented signal (signal 21, status 0)" after using little-endian? If so, could you get a sniffer log of the behavior and upload it here as a pcap file? Please make sure to start the sniffer before starting the network so the sniffer has the network key. You can use nRF Sniffer for 802.15.4 to get a sniffer log if you have an additional nRF52840 DK or Dongle.

    Best regards,

    Marte

  • Hi Marte,

    Thank you for clarifying the byte-order. However, with the correct endianness, the bind still fails.

    I do have a third NRF52840DK which I can configure as a nRF sniffer. I looked at the installation guide, added the files to /extcap (Python file and .bat file), configured the preferences but I cannot find the extcap option for the nrf sniffer in WireShark itself. I am currently on a macOS Big Sur (M1). However, the installation guide is quite unclear for mac users.

    Best regards,

    Sebastiaan

  • Hi Sebastiaan,

    Then there is something else wrong with the command. Getting a sniffer log would be very helpful for figuring out what might be causing it.

    I am sorry about that. The guide under nRF Tools in the documentation has guides for installing on macOS as well: nRF Sniffer for 802.15.4. For installing the plugin in Wireshark you can check out Installing the nRF Sniffer capture plugin in Wireshark.

    Best regards,

    Marte

Reply Children
  • Hello Marte,

    I am trying the link you suggested. What I've done so far:

    • Flashed the third NRF52 development kit with the 'nrf802154_sniffer.hex' file.
    • Copied the nrf802154_sniffer.py into the Global Extcap path of WireShark (/Applications/Wireshark.app/Contents/MacOS/extcap)
    • Verified that the file can be ran and that the output is the same as the tutorial

    The response of running the python file is:

    extcap {version=0.7.2}{help=github.com/.../nRF-Sniffer-for-802.15.4}{display=nRF Sniffer for 802.15.4}
    control {number=6}{type=button}{role=logger}{display=Log}{tooltip=Show capture log}

    However, when I boot WireShark, the NRF extcap is not detected. Any idea what could be the cause?

    Thanks in advance,

    Sebastiaan

  • Hi Sebastiaan,

    The response should contain a list of available interfaces, but there are no interfaces in your response, so the tool does not see your device. If you are using a DK for the sniffer you must use the nRF USB, not the USB connecter J2, as seen in Connecting the sniffer to the host.

    Best regards,

    Marte

Related