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

Mesh network durations

Hi, 

I created a mesh network with a mesh model which allows me to send a string message over it.

I use one board with a provisioning role and 3 others as provisionee. When i add them to the mesh networks, it takes about 3 minutes per device. Do you have any idea on how i can reduce this duration ? 

If I want to send 50 packets of 20 bytes over BLE Mesh, do you have any idea on the time it would take to send and receive all of them ? 

Thank you.

Parents
  • My code is based on the light_switch example from mesh v1.0.1. I am able to send a message when i press a button (instead of turning on or off a led as in the example). When i try to send several messages with a for loop and a delay, it seems that four message are sent but it does not work for more and i do not understand why. I get the "NRF_ERROR_NO_MEM" error which seem coming from "allocate_packet" in network.c but i do not know how to avoid it.

       3416942>, main.c,  438, Configuration of device 0 successful
    <t:   14664022>, main.c,  380, Button 0 pressed
    <t:   14695281>, access.c,  517, TX: [aop: 0x00D1]
    <t:   14695283>, simple_message.c,  137, Status : 0 
    <t:   14757771>, access.c,  517, TX: [aop: 0x00D1]
    <t:   14757773>, simple_message.c,  137, Status : 0 
    <t:   14820241>, access.c,  517, TX: [aop: 0x00D1]
    <t:   14820244>, simple_message.c,  137, Status : 0 
    <t:   14882712>, access.c,  517, TX: [aop: 0x00D1]
    <t:   14882714>, simple_message.c,  137, Status : 0 
    <t:   14945182>, simple_message.c,  137, Status : 4 
    <t:   14945184>, simple_message.c,  141, Cannot send. Device is busy.
    <t:   14945187>, main.c,  372, Fail sending REQUEST

    On the server side, i only receive one message:

    <t:          0>, main.c,  170, ----- BLE Mesh Light Switch Server Demo -----
    <t:        302>, main.c,   98, Initializing and adding models
    <t:    1190954>, access.c,  346, RX: [aop: 0x8008]
    <t:    1190977>, access.c,  517, TX: [aop: 0x0002]
    <t:    1242553>, main.c,  114, Successfully provisioned
    <t:    1314888>, access.c,  346, RX: [aop: 0x0000]
    <t:    1891329>, access.c,  346, RX: [aop: 0x0000]
    <t:    1891339>, access.c,  517, TX: [aop: 0x8003]
    <t:    2416110>, access.c,  346, RX: [aop: 0x803D]
    <t:    2416123>, access.c,  517, TX: [aop: 0x803E]
    <t:    2462174>, access.c,  346, RX: [aop: 0x803D]
    <t:    2462186>, access.c,  517, TX: [aop: 0x803E]
    <t:    2536929>, access.c,  346, RX: [aop: 0x0003]
    <t:    2536946>, access.c,  517, TX: [aop: 0x8019]
    <t:    3156584>, access.c,  346, RX: [aop: 0x0003]
    <t:    3156600>, access.c,  517, TX: [aop: 0x8019]
    <t:    3387223>, access.c,  346, RX: [aop: 0x0003]
    <t:    3387239>, access.c,  517, TX: [aop: 0x8019]
    <t:    3584899>, access.c,  346, RX: [aop: 0x801B]
    <t:    3584911>, access.c,  517, TX: [aop: 0x801F]
    <t:    3782024>, access.c,  346, RX: [aop: 0x801B]
    <t:    3782035>, access.c,  517, TX: [aop: 0x801F]
    <t:   15404479>, access.c,  346, RX: [aop: 0x00D1]
    <t:   15404481>, main.c,  140, Got Request Message
    <t:   15404484>, main.c,  141, Node 0x0001 RSSI: -25    TTL:  5  
    <t:   15404487>, main.c,  142, Message: Message de 20 bytes

    Before, when my code was able to send a message everytime i pressed the button with no limitations.

    Could you help me finding what i am doing wrong ? 

    I show you my client code:

    /* Copyright (c) 2010 - 2017, Nordic Semiconductor ASA
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     * list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include <stdint.h>
    #include <string.h>
    
    /* HAL */
    #include "nrf.h"
    #include "nrf_sdm.h"
    #include "boards.h"
    #include "nrf_mesh_sdk.h"
    #include "nrf_delay.h"
    
    /* Core */
    #include "nrf_mesh.h"
    #include "nrf_mesh_events.h"
    #include "nrf_mesh_prov.h"
    #include "nrf_mesh_assert.h"
    #include "log.h"
    
    #include "access.h"
    #include "access_config.h"
    #include "device_state_manager.h"
    
    #include "config_client.h"
    //#include "health_client.h"
    #include "simple_on_off_client.h"
    #include "simple_message.h"
    
    #include "simple_hal.h"
    #include "provisioner.h"
    
    #include "light_switch_example_common.h"
    #include "rtt_input.h"
    #include "SEGGER_RTT.h"
    
    /*****************************************************************************
     * Definitions
     *****************************************************************************/
    
    #define CLIENT_COUNT             (SERVER_COUNT + 1)
    #define GROUP_CLIENT_INDEX       (SERVER_COUNT)
    #define BUTTON_NUMBER_GROUP      (3)
    #define RTT_INPUT_POLL_PERIOD_MS (100)
    
    /*****************************************************************************
     * Static data
     *****************************************************************************/
    
    static const uint8_t m_netkey[NRF_MESH_KEY_SIZE] = NETKEY;
    static const uint8_t m_appkey[NRF_MESH_KEY_SIZE] = APPKEY;
    
    static dsm_handle_t m_netkey_handle;
    static dsm_handle_t m_appkey_handle;
    static dsm_handle_t m_devkey_handles[SERVER_COUNT];
    static dsm_handle_t m_server_handles[SERVER_COUNT];
    static dsm_handle_t m_group_handle;
    static dsm_handle_t m_central_handle;
    
    static simple_on_off_client_t m_clients[CLIENT_COUNT];
    //static health_client_t m_health_client;
    static simple_message_t m_message_client;
    
    static uint16_t m_provisioned_devices;
    static uint16_t m_configured_devices;
    
    /* Forward declarations */
    static void client_status_cb(const simple_on_off_client_t * p_self, simple_on_off_status_t status, uint16_t src);
    //static void health_event_cb(const health_client_t * p_client, const health_client_evt_t * p_event);
    static bool request_message_cb(const simple_message_t * p_client, const access_message_rx_t * p_message);
    static bool response_message_cb(const simple_message_t * p_client, const access_message_rx_t * p_message);
    /*****************************************************************************
     * Static functions
     *****************************************************************************/
    
    /**
     * Retrieves stored device state manager configuration.
     * The number of provisioned devices is calculated from the number of device keys stored. The device
     * key for each server is stored on provisioning complete in the `provisioner_prov_complete_cb()`.
     *
     * @returns Number of provisioned devices.
     */
    static uint16_t provisioned_device_handles_load(void)
    {
        uint16_t provisioned_devices = 0;
    
        /* Load the key handles. */
        uint32_t count = 1;
        ERROR_CHECK(dsm_subnet_get_all(&m_netkey_handle, &count));
        count = 1;
        ERROR_CHECK(dsm_appkey_get_all(m_netkey_handle, &m_appkey_handle, &count));
    
        /* Load all the address handles. */
        dsm_handle_t address_handles[DSM_ADDR_MAX];
        count = DSM_NONVIRTUAL_ADDR_MAX;
        ERROR_CHECK(dsm_address_get_all(&address_handles[0], &count));
    
        for (uint32_t i = 0; i < count; ++i)
        {
            nrf_mesh_address_t address;
            ERROR_CHECK(dsm_address_get(address_handles[i], &address));
    
            /* If the address is a unicast address, it is one of the server's root element address and
             * we have should have a device key stored for it. If not, it is our GROUP_ADDRESS and we
             * load the handle for that.
             */
            if ((address.type == NRF_MESH_ADDRESS_TYPE_UNICAST) &&
                (dsm_devkey_handle_get(address.value, &m_devkey_handles[provisioned_devices]) == NRF_SUCCESS)
                && m_devkey_handles[provisioned_devices] != DSM_HANDLE_INVALID)
            {
                ERROR_CHECK(dsm_address_handle_get(&address, &m_server_handles[provisioned_devices]));
                provisioned_devices++;
            }
            else if (address.type == NRF_MESH_ADDRESS_TYPE_GROUP)
            {
                ERROR_CHECK(dsm_address_handle_get(&address, &m_group_handle));
            }
        }
    
        return provisioned_devices;
    }
    
    /**
     * Gets the number of configured devices.
     *
     * We exploit the fact that the publish address of the Simple OnOff clients is set at configuration
     * complete, i.e., in the `provisioner_config_successful_cb()`, and simply count the number of
     * clients with their publish address' set.
     */
    static uint16_t configured_devices_count_get(void)
    {
        uint16_t configured_devices = 0;
        for (uint32_t i = 0; i < SERVER_COUNT; ++i)
        {
            dsm_handle_t address_handle = DSM_HANDLE_INVALID;
            if ((access_model_publish_address_get(m_clients[i].model_handle,
                                                  &address_handle) == NRF_SUCCESS)
                && (DSM_HANDLE_INVALID != address_handle))
            {
                configured_devices++;
            }
            else
            {
                /* Clients are configured sequentially. */
                break;
            }
        }
    
        return configured_devices;
    }
    
    static void access_setup(void)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Setting up access layer and models\n");
    
        dsm_init();
        access_init();
    
        m_netkey_handle = DSM_HANDLE_INVALID;
        m_appkey_handle = DSM_HANDLE_INVALID;
        for (uint32_t i = 0; i < SERVER_COUNT; ++i)
        {
            m_devkey_handles[i] = DSM_HANDLE_INVALID;
            m_server_handles[i] = DSM_HANDLE_INVALID;
        }
        m_group_handle = DSM_HANDLE_INVALID;
    
        /* Initialize and enable all the models before calling ***_flash_config_load. */
        ERROR_CHECK(config_client_init(config_client_event_cb));
        //ERROR_CHECK(health_client_init(&m_health_client, 0, health_event_cb));
        m_message_client.message_request_cb  = request_message_cb;
        m_message_client.message_response_cb = response_message_cb;
        ERROR_CHECK(simple_message_init(&m_message_client, 0));
    
        for (uint32_t i = 0; i < CLIENT_COUNT; ++i)
        {
            m_clients[i].status_cb = client_status_cb;
            ERROR_CHECK(simple_on_off_client_init(&m_clients[i], i));
        }
    
        if (dsm_flash_config_load())
        {
            m_provisioned_devices = provisioned_device_handles_load();
        }
        else
        {
            /* Set and add local addresses and keys, if flash recovery fails. */
            dsm_local_unicast_address_t local_address = {PROVISIONER_ADDRESS, ACCESS_ELEMENT_COUNT};
            ERROR_CHECK(dsm_local_unicast_addresses_set(&local_address));
            ERROR_CHECK(dsm_address_publish_add(GROUP_ADDRESS, &m_group_handle));
            ERROR_CHECK(dsm_subnet_add(0, m_netkey, &m_netkey_handle));
            ERROR_CHECK(dsm_appkey_add(0, m_netkey_handle, m_appkey, &m_appkey_handle));
        }
    
        if (access_flash_config_load())
        {
            m_configured_devices = configured_devices_count_get();
        }
        else
        {
            /* Bind the keys to the health client. */
            //ERROR_CHECK(access_model_application_bind(m_health_client.model_handle, m_appkey_handle));
            //ERROR_CHECK(access_model_publish_application_set(m_health_client.model_handle, m_appkey_handle));
    
            /* Bind the keys to the message client. */
            ERROR_CHECK(access_model_application_bind(m_message_client.model_handle, m_appkey_handle));
            ERROR_CHECK(access_model_publish_application_set(m_message_client.model_handle, m_appkey_handle));
    
            /* Bind the keys to the Simple OnOff clients. */
            for (uint32_t i = 0; i < SERVER_COUNT; ++i)
            {
                ERROR_CHECK(access_model_application_bind(m_clients[i].model_handle, m_appkey_handle));
                ERROR_CHECK(access_model_publish_application_set(m_clients[i].model_handle, m_appkey_handle));
            }
    
            ERROR_CHECK(access_model_application_bind(m_clients[GROUP_CLIENT_INDEX].model_handle, m_appkey_handle));
            ERROR_CHECK(access_model_publish_application_set(m_clients[GROUP_CLIENT_INDEX].model_handle, m_appkey_handle));
            ERROR_CHECK(access_model_publish_address_set(m_clients[GROUP_CLIENT_INDEX].model_handle, m_group_handle));
            access_flash_config_store();
        }
    
        provisioner_init();
        if (m_configured_devices < m_provisioned_devices)
        {
            provisioner_configure(UNPROV_START_ADDRESS + m_configured_devices);
        }
        else if (m_provisioned_devices < SERVER_COUNT)
        {
            provisioner_wait_for_unprov(UNPROV_START_ADDRESS + m_provisioned_devices);
        }
    }
    
    static uint32_t server_index_get(const simple_on_off_client_t * p_client)
    {
        uint32_t index = (((uint32_t) p_client - ((uint32_t) &m_clients[0]))) / sizeof(m_clients[0]);
        NRF_MESH_ASSERT(index < SERVER_COUNT);
        return index;
    }
    
    static void client_status_cb(const simple_on_off_client_t * p_self, simple_on_off_status_t status, uint16_t src)
    {
        uint32_t server_index = server_index_get(p_self);
        switch (status)
        {
            case SIMPLE_ON_OFF_STATUS_ON:
                hal_led_pin_set(BSP_LED_0 + server_index, true);
                break;
    
            case SIMPLE_ON_OFF_STATUS_OFF:
                hal_led_pin_set(BSP_LED_0 + server_index, false);
                break;
    
            case SIMPLE_ON_OFF_STATUS_ERROR_NO_REPLY:
                hal_led_blink_ms(LEDS_MASK, 100, 6);
                break;
    
            default:
                NRF_MESH_ASSERT(false);
                break;
        }
    
        /* Set 4th LED on when all servers are on. */
        bool all_servers_on = true;
        for (uint32_t i = BSP_LED_0; i < BSP_LED_0 + m_configured_devices; ++i)
        {
            if (!hal_led_pin_get(i))
            {
                all_servers_on = false;
                break;
            }
        }
    
        hal_led_pin_set(BSP_LED_3, all_servers_on);
    }
    static bool request_message_cb(const simple_message_t * p_client, const access_message_rx_t * p_message)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Got Request Message");
    }
    
    /*
    static void health_event_cb(const health_client_t * p_client, const health_client_evt_t * p_event)
    {
        switch (p_event->type)
        {
            case HEALTH_CLIENT_EVT_TYPE_CURRENT_STATUS_RECEIVED:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Node 0x%04x alive with %u active fault(s), RSSI: %d\n",
                      p_event->p_meta_data->src.value, p_event->data.fault_status.fault_array_length,
                      p_event->p_meta_data->rssi);
                break;
            default:
                break;
        }
    }*/
    
    
    static bool response_message_cb(const simple_message_t * p_client,  const access_message_rx_t * p_message)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Got Message\n");
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Node 0x%04x RSSI: %d    TTL:  %u  \n", p_message->meta_data.src.value, p_message->meta_data.rssi, p_message->meta_data.ttl);
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Message: Device: %c%c%c%c%c%c%c%c%c PosX: %x%x PosY: %x%x PosZ: %x%x Batt: %u%%  \n ",p_message->p_data[7],p_message->p_data[8],p_message->p_data[9],p_message->p_data[10],p_message->p_data[11],p_message->p_data[12],p_message->p_data[13],p_message->p_data[14],p_message->p_data[15],p_message->p_data[0], p_message->p_data[1], p_message->p_data[2], p_message->p_data[3], p_message->p_data[4], p_message->p_data[5], p_message->p_data[6]);
    
        return true; // to modify
    }
    
    void address_set(uint16_t addr)
    {
       ERROR_CHECK(dsm_address_publish_add(addr, &m_central_handle));
       ERROR_CHECK(access_model_publish_address_set(m_server_handles[0], m_central_handle));
     }
    
    void send_my_message (uint32_t target) 
    {
        uint8_t buffer[15]="Where are you ?";
        uint8_t length;
        uint16_t address;
        length= sizeof(buffer);
        if ( target == GROUP_CLIENT_INDEX )
        {
            address = 0xCAFE;
            address_set(address);
            SEGGER_RTT_printf(0,"Sending to group address 0x%04x\n", address);
        }
        if ( simple_message_send(m_clients[target].model_handle, buffer, length, SIMPLE_MESSAGE_OPCODE_REQUEST) )
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Fail sending REQUEST\n");        
        }
    }
    
    void send_my_50_message (uint32_t target, char c) 
    {
        uint8_t buffer[20]="Message de 20 bytes";
        buffer[19]=(uint8_t)c;
        uint8_t length;
        uint16_t address;
        length= sizeof(buffer);
        if (simple_message_send(m_clients[target].model_handle, buffer, length, SIMPLE_MESSAGE_OPCODE_REQUEST) )
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Fail sending REQUEST\n");        
        }
        nrf_delay_us(1000000);
    }
    
    
    static void button_event_handler(uint32_t button_number)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Button %u pressed\n", button_number);
        if (m_configured_devices == 0)
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_WARN, "No devices provisioned\n");
            return;
        }
        else if (m_configured_devices <= button_number && button_number != BUTTON_NUMBER_GROUP)
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_WARN, "Device %u not provisioned yet.\n", button_number);
            return;
        }
    
        uint32_t status = NRF_SUCCESS;
        switch (button_number)
        {
            case 0:
            case 1:
            case 2:
                /* Invert LED. */
                //status = simple_on_off_client_set(&m_clients[button_number],
                //!hal_led_pin_get(BSP_LED_0 + button_number));
                //send_my_message(button_number);
                for ( uint8_t i=0 ; i < 5 ; i++)
                {
                    nrf_delay_us(1000000);
                    send_my_50_message(button_number,i);
                }
                break;
            case 3:
                /* Group message: invert all LEDs. */
                //status = simple_on_off_client_set_unreliable(&m_clients[GROUP_CLIENT_INDEX],
                //                                             !hal_led_pin_get(BSP_LED_0 + button_number), 3);
                send_my_message(button_number);
                break;
            default:
                break;
    
        }
    
        if (status == NRF_ERROR_INVALID_STATE ||
            status == NRF_ERROR_NO_MEM ||
            status == NRF_ERROR_BUSY)
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Cannot send. Device is busy.\n");
            hal_led_blink_ms(LEDS_MASK, 50, 4);
        }
        else
        {
            ERROR_CHECK(status);
        }
    }
    
    /*****************************************************************************
     * Event callbacks from the provisioner
     *****************************************************************************/
    
    void provisioner_config_successful_cb(void)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Configuration of device %u successful\n", m_configured_devices);
    
        /* Set publish address for the client to the corresponding server. */
        ERROR_CHECK(access_model_publish_address_set(m_clients[m_configured_devices].model_handle,
                                                     m_server_handles[m_configured_devices]));
        access_flash_config_store();
    
        hal_led_pin_set(BSP_LED_0 + m_configured_devices, false);
        m_configured_devices++;
    
        if (m_configured_devices < SERVER_COUNT)
        {
            provisioner_wait_for_unprov(UNPROV_START_ADDRESS + m_provisioned_devices);
            hal_led_pin_set(BSP_LED_0 + m_configured_devices, true);
        }
        else
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "All servers provisioned\n");
            hal_led_blink_ms(LEDS_MASK, 100, 4);
        }
    }
    
    void provisioner_config_failed_cb(void)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Configuration of device %u failed\n", m_configured_devices);
    
        /* Delete key and address. */
        ERROR_CHECK(dsm_address_publish_remove(m_server_handles[m_configured_devices]));
        ERROR_CHECK(dsm_devkey_delete(m_devkey_handles[m_configured_devices]));
        provisioner_wait_for_unprov(UNPROV_START_ADDRESS + m_provisioned_devices);
    }
    
    void provisioner_prov_complete_cb(const nrf_mesh_prov_evt_complete_t * p_prov_data)
    {
        /* We should not get here if all servers are provisioned. */
        NRF_MESH_ASSERT(m_configured_devices < SERVER_COUNT);
    
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Provisioning complete. Adding address 0x%04x.\n", p_prov_data->address);
    
        /* Add to local storage. */
        ERROR_CHECK(dsm_address_publish_add(p_prov_data->address, &m_server_handles[m_provisioned_devices]));
        ERROR_CHECK(dsm_devkey_add(p_prov_data->address, m_netkey_handle, p_prov_data->p_devkey, &m_devkey_handles[m_provisioned_devices]));
    
        /* Bind the device key to the configuration server and set the new node as the active server. */
        ERROR_CHECK(config_client_server_bind(m_devkey_handles[m_provisioned_devices]));
        ERROR_CHECK(config_client_server_set(m_devkey_handles[m_provisioned_devices],
                                             m_server_handles[m_provisioned_devices]));
    
        m_provisioned_devices++;
    
        /* Move on to the configuration step. */
        provisioner_configure(UNPROV_START_ADDRESS + m_configured_devices);
    }
    
    static void rtt_input_handler(int key)
    {
        if (key >= '0' && key <= '3')
        {
            uint32_t button_number = key - '0';
            button_event_handler(button_number);
        }
    }
    
    int main(void)
    {
        __LOG_INIT(LOG_SRC_APP | LOG_SRC_ACCESS, LOG_LEVEL_DBG1, LOG_CALLBACK_DEFAULT);
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- BLE Mesh Light Switch Client Demo -----\n");
    
        hal_leds_init();
        ERROR_CHECK(hal_buttons_init(button_event_handler));
    
        /* Set the first LED */
        hal_led_pin_set(BSP_LED_0, true);
        mesh_core_setup();
        access_setup();
        rtt_input_enable(rtt_input_handler, RTT_INPUT_POLL_PERIOD_MS);
    
        while (true)
        {
            (void)sd_app_evt_wait();
        }
    }
    

Reply
  • My code is based on the light_switch example from mesh v1.0.1. I am able to send a message when i press a button (instead of turning on or off a led as in the example). When i try to send several messages with a for loop and a delay, it seems that four message are sent but it does not work for more and i do not understand why. I get the "NRF_ERROR_NO_MEM" error which seem coming from "allocate_packet" in network.c but i do not know how to avoid it.

       3416942>, main.c,  438, Configuration of device 0 successful
    <t:   14664022>, main.c,  380, Button 0 pressed
    <t:   14695281>, access.c,  517, TX: [aop: 0x00D1]
    <t:   14695283>, simple_message.c,  137, Status : 0 
    <t:   14757771>, access.c,  517, TX: [aop: 0x00D1]
    <t:   14757773>, simple_message.c,  137, Status : 0 
    <t:   14820241>, access.c,  517, TX: [aop: 0x00D1]
    <t:   14820244>, simple_message.c,  137, Status : 0 
    <t:   14882712>, access.c,  517, TX: [aop: 0x00D1]
    <t:   14882714>, simple_message.c,  137, Status : 0 
    <t:   14945182>, simple_message.c,  137, Status : 4 
    <t:   14945184>, simple_message.c,  141, Cannot send. Device is busy.
    <t:   14945187>, main.c,  372, Fail sending REQUEST

    On the server side, i only receive one message:

    <t:          0>, main.c,  170, ----- BLE Mesh Light Switch Server Demo -----
    <t:        302>, main.c,   98, Initializing and adding models
    <t:    1190954>, access.c,  346, RX: [aop: 0x8008]
    <t:    1190977>, access.c,  517, TX: [aop: 0x0002]
    <t:    1242553>, main.c,  114, Successfully provisioned
    <t:    1314888>, access.c,  346, RX: [aop: 0x0000]
    <t:    1891329>, access.c,  346, RX: [aop: 0x0000]
    <t:    1891339>, access.c,  517, TX: [aop: 0x8003]
    <t:    2416110>, access.c,  346, RX: [aop: 0x803D]
    <t:    2416123>, access.c,  517, TX: [aop: 0x803E]
    <t:    2462174>, access.c,  346, RX: [aop: 0x803D]
    <t:    2462186>, access.c,  517, TX: [aop: 0x803E]
    <t:    2536929>, access.c,  346, RX: [aop: 0x0003]
    <t:    2536946>, access.c,  517, TX: [aop: 0x8019]
    <t:    3156584>, access.c,  346, RX: [aop: 0x0003]
    <t:    3156600>, access.c,  517, TX: [aop: 0x8019]
    <t:    3387223>, access.c,  346, RX: [aop: 0x0003]
    <t:    3387239>, access.c,  517, TX: [aop: 0x8019]
    <t:    3584899>, access.c,  346, RX: [aop: 0x801B]
    <t:    3584911>, access.c,  517, TX: [aop: 0x801F]
    <t:    3782024>, access.c,  346, RX: [aop: 0x801B]
    <t:    3782035>, access.c,  517, TX: [aop: 0x801F]
    <t:   15404479>, access.c,  346, RX: [aop: 0x00D1]
    <t:   15404481>, main.c,  140, Got Request Message
    <t:   15404484>, main.c,  141, Node 0x0001 RSSI: -25    TTL:  5  
    <t:   15404487>, main.c,  142, Message: Message de 20 bytes

    Before, when my code was able to send a message everytime i pressed the button with no limitations.

    Could you help me finding what i am doing wrong ? 

    I show you my client code:

    /* Copyright (c) 2010 - 2017, Nordic Semiconductor ASA
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     * list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include <stdint.h>
    #include <string.h>
    
    /* HAL */
    #include "nrf.h"
    #include "nrf_sdm.h"
    #include "boards.h"
    #include "nrf_mesh_sdk.h"
    #include "nrf_delay.h"
    
    /* Core */
    #include "nrf_mesh.h"
    #include "nrf_mesh_events.h"
    #include "nrf_mesh_prov.h"
    #include "nrf_mesh_assert.h"
    #include "log.h"
    
    #include "access.h"
    #include "access_config.h"
    #include "device_state_manager.h"
    
    #include "config_client.h"
    //#include "health_client.h"
    #include "simple_on_off_client.h"
    #include "simple_message.h"
    
    #include "simple_hal.h"
    #include "provisioner.h"
    
    #include "light_switch_example_common.h"
    #include "rtt_input.h"
    #include "SEGGER_RTT.h"
    
    /*****************************************************************************
     * Definitions
     *****************************************************************************/
    
    #define CLIENT_COUNT             (SERVER_COUNT + 1)
    #define GROUP_CLIENT_INDEX       (SERVER_COUNT)
    #define BUTTON_NUMBER_GROUP      (3)
    #define RTT_INPUT_POLL_PERIOD_MS (100)
    
    /*****************************************************************************
     * Static data
     *****************************************************************************/
    
    static const uint8_t m_netkey[NRF_MESH_KEY_SIZE] = NETKEY;
    static const uint8_t m_appkey[NRF_MESH_KEY_SIZE] = APPKEY;
    
    static dsm_handle_t m_netkey_handle;
    static dsm_handle_t m_appkey_handle;
    static dsm_handle_t m_devkey_handles[SERVER_COUNT];
    static dsm_handle_t m_server_handles[SERVER_COUNT];
    static dsm_handle_t m_group_handle;
    static dsm_handle_t m_central_handle;
    
    static simple_on_off_client_t m_clients[CLIENT_COUNT];
    //static health_client_t m_health_client;
    static simple_message_t m_message_client;
    
    static uint16_t m_provisioned_devices;
    static uint16_t m_configured_devices;
    
    /* Forward declarations */
    static void client_status_cb(const simple_on_off_client_t * p_self, simple_on_off_status_t status, uint16_t src);
    //static void health_event_cb(const health_client_t * p_client, const health_client_evt_t * p_event);
    static bool request_message_cb(const simple_message_t * p_client, const access_message_rx_t * p_message);
    static bool response_message_cb(const simple_message_t * p_client, const access_message_rx_t * p_message);
    /*****************************************************************************
     * Static functions
     *****************************************************************************/
    
    /**
     * Retrieves stored device state manager configuration.
     * The number of provisioned devices is calculated from the number of device keys stored. The device
     * key for each server is stored on provisioning complete in the `provisioner_prov_complete_cb()`.
     *
     * @returns Number of provisioned devices.
     */
    static uint16_t provisioned_device_handles_load(void)
    {
        uint16_t provisioned_devices = 0;
    
        /* Load the key handles. */
        uint32_t count = 1;
        ERROR_CHECK(dsm_subnet_get_all(&m_netkey_handle, &count));
        count = 1;
        ERROR_CHECK(dsm_appkey_get_all(m_netkey_handle, &m_appkey_handle, &count));
    
        /* Load all the address handles. */
        dsm_handle_t address_handles[DSM_ADDR_MAX];
        count = DSM_NONVIRTUAL_ADDR_MAX;
        ERROR_CHECK(dsm_address_get_all(&address_handles[0], &count));
    
        for (uint32_t i = 0; i < count; ++i)
        {
            nrf_mesh_address_t address;
            ERROR_CHECK(dsm_address_get(address_handles[i], &address));
    
            /* If the address is a unicast address, it is one of the server's root element address and
             * we have should have a device key stored for it. If not, it is our GROUP_ADDRESS and we
             * load the handle for that.
             */
            if ((address.type == NRF_MESH_ADDRESS_TYPE_UNICAST) &&
                (dsm_devkey_handle_get(address.value, &m_devkey_handles[provisioned_devices]) == NRF_SUCCESS)
                && m_devkey_handles[provisioned_devices] != DSM_HANDLE_INVALID)
            {
                ERROR_CHECK(dsm_address_handle_get(&address, &m_server_handles[provisioned_devices]));
                provisioned_devices++;
            }
            else if (address.type == NRF_MESH_ADDRESS_TYPE_GROUP)
            {
                ERROR_CHECK(dsm_address_handle_get(&address, &m_group_handle));
            }
        }
    
        return provisioned_devices;
    }
    
    /**
     * Gets the number of configured devices.
     *
     * We exploit the fact that the publish address of the Simple OnOff clients is set at configuration
     * complete, i.e., in the `provisioner_config_successful_cb()`, and simply count the number of
     * clients with their publish address' set.
     */
    static uint16_t configured_devices_count_get(void)
    {
        uint16_t configured_devices = 0;
        for (uint32_t i = 0; i < SERVER_COUNT; ++i)
        {
            dsm_handle_t address_handle = DSM_HANDLE_INVALID;
            if ((access_model_publish_address_get(m_clients[i].model_handle,
                                                  &address_handle) == NRF_SUCCESS)
                && (DSM_HANDLE_INVALID != address_handle))
            {
                configured_devices++;
            }
            else
            {
                /* Clients are configured sequentially. */
                break;
            }
        }
    
        return configured_devices;
    }
    
    static void access_setup(void)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Setting up access layer and models\n");
    
        dsm_init();
        access_init();
    
        m_netkey_handle = DSM_HANDLE_INVALID;
        m_appkey_handle = DSM_HANDLE_INVALID;
        for (uint32_t i = 0; i < SERVER_COUNT; ++i)
        {
            m_devkey_handles[i] = DSM_HANDLE_INVALID;
            m_server_handles[i] = DSM_HANDLE_INVALID;
        }
        m_group_handle = DSM_HANDLE_INVALID;
    
        /* Initialize and enable all the models before calling ***_flash_config_load. */
        ERROR_CHECK(config_client_init(config_client_event_cb));
        //ERROR_CHECK(health_client_init(&m_health_client, 0, health_event_cb));
        m_message_client.message_request_cb  = request_message_cb;
        m_message_client.message_response_cb = response_message_cb;
        ERROR_CHECK(simple_message_init(&m_message_client, 0));
    
        for (uint32_t i = 0; i < CLIENT_COUNT; ++i)
        {
            m_clients[i].status_cb = client_status_cb;
            ERROR_CHECK(simple_on_off_client_init(&m_clients[i], i));
        }
    
        if (dsm_flash_config_load())
        {
            m_provisioned_devices = provisioned_device_handles_load();
        }
        else
        {
            /* Set and add local addresses and keys, if flash recovery fails. */
            dsm_local_unicast_address_t local_address = {PROVISIONER_ADDRESS, ACCESS_ELEMENT_COUNT};
            ERROR_CHECK(dsm_local_unicast_addresses_set(&local_address));
            ERROR_CHECK(dsm_address_publish_add(GROUP_ADDRESS, &m_group_handle));
            ERROR_CHECK(dsm_subnet_add(0, m_netkey, &m_netkey_handle));
            ERROR_CHECK(dsm_appkey_add(0, m_netkey_handle, m_appkey, &m_appkey_handle));
        }
    
        if (access_flash_config_load())
        {
            m_configured_devices = configured_devices_count_get();
        }
        else
        {
            /* Bind the keys to the health client. */
            //ERROR_CHECK(access_model_application_bind(m_health_client.model_handle, m_appkey_handle));
            //ERROR_CHECK(access_model_publish_application_set(m_health_client.model_handle, m_appkey_handle));
    
            /* Bind the keys to the message client. */
            ERROR_CHECK(access_model_application_bind(m_message_client.model_handle, m_appkey_handle));
            ERROR_CHECK(access_model_publish_application_set(m_message_client.model_handle, m_appkey_handle));
    
            /* Bind the keys to the Simple OnOff clients. */
            for (uint32_t i = 0; i < SERVER_COUNT; ++i)
            {
                ERROR_CHECK(access_model_application_bind(m_clients[i].model_handle, m_appkey_handle));
                ERROR_CHECK(access_model_publish_application_set(m_clients[i].model_handle, m_appkey_handle));
            }
    
            ERROR_CHECK(access_model_application_bind(m_clients[GROUP_CLIENT_INDEX].model_handle, m_appkey_handle));
            ERROR_CHECK(access_model_publish_application_set(m_clients[GROUP_CLIENT_INDEX].model_handle, m_appkey_handle));
            ERROR_CHECK(access_model_publish_address_set(m_clients[GROUP_CLIENT_INDEX].model_handle, m_group_handle));
            access_flash_config_store();
        }
    
        provisioner_init();
        if (m_configured_devices < m_provisioned_devices)
        {
            provisioner_configure(UNPROV_START_ADDRESS + m_configured_devices);
        }
        else if (m_provisioned_devices < SERVER_COUNT)
        {
            provisioner_wait_for_unprov(UNPROV_START_ADDRESS + m_provisioned_devices);
        }
    }
    
    static uint32_t server_index_get(const simple_on_off_client_t * p_client)
    {
        uint32_t index = (((uint32_t) p_client - ((uint32_t) &m_clients[0]))) / sizeof(m_clients[0]);
        NRF_MESH_ASSERT(index < SERVER_COUNT);
        return index;
    }
    
    static void client_status_cb(const simple_on_off_client_t * p_self, simple_on_off_status_t status, uint16_t src)
    {
        uint32_t server_index = server_index_get(p_self);
        switch (status)
        {
            case SIMPLE_ON_OFF_STATUS_ON:
                hal_led_pin_set(BSP_LED_0 + server_index, true);
                break;
    
            case SIMPLE_ON_OFF_STATUS_OFF:
                hal_led_pin_set(BSP_LED_0 + server_index, false);
                break;
    
            case SIMPLE_ON_OFF_STATUS_ERROR_NO_REPLY:
                hal_led_blink_ms(LEDS_MASK, 100, 6);
                break;
    
            default:
                NRF_MESH_ASSERT(false);
                break;
        }
    
        /* Set 4th LED on when all servers are on. */
        bool all_servers_on = true;
        for (uint32_t i = BSP_LED_0; i < BSP_LED_0 + m_configured_devices; ++i)
        {
            if (!hal_led_pin_get(i))
            {
                all_servers_on = false;
                break;
            }
        }
    
        hal_led_pin_set(BSP_LED_3, all_servers_on);
    }
    static bool request_message_cb(const simple_message_t * p_client, const access_message_rx_t * p_message)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Got Request Message");
    }
    
    /*
    static void health_event_cb(const health_client_t * p_client, const health_client_evt_t * p_event)
    {
        switch (p_event->type)
        {
            case HEALTH_CLIENT_EVT_TYPE_CURRENT_STATUS_RECEIVED:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Node 0x%04x alive with %u active fault(s), RSSI: %d\n",
                      p_event->p_meta_data->src.value, p_event->data.fault_status.fault_array_length,
                      p_event->p_meta_data->rssi);
                break;
            default:
                break;
        }
    }*/
    
    
    static bool response_message_cb(const simple_message_t * p_client,  const access_message_rx_t * p_message)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Got Message\n");
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Node 0x%04x RSSI: %d    TTL:  %u  \n", p_message->meta_data.src.value, p_message->meta_data.rssi, p_message->meta_data.ttl);
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Message: Device: %c%c%c%c%c%c%c%c%c PosX: %x%x PosY: %x%x PosZ: %x%x Batt: %u%%  \n ",p_message->p_data[7],p_message->p_data[8],p_message->p_data[9],p_message->p_data[10],p_message->p_data[11],p_message->p_data[12],p_message->p_data[13],p_message->p_data[14],p_message->p_data[15],p_message->p_data[0], p_message->p_data[1], p_message->p_data[2], p_message->p_data[3], p_message->p_data[4], p_message->p_data[5], p_message->p_data[6]);
    
        return true; // to modify
    }
    
    void address_set(uint16_t addr)
    {
       ERROR_CHECK(dsm_address_publish_add(addr, &m_central_handle));
       ERROR_CHECK(access_model_publish_address_set(m_server_handles[0], m_central_handle));
     }
    
    void send_my_message (uint32_t target) 
    {
        uint8_t buffer[15]="Where are you ?";
        uint8_t length;
        uint16_t address;
        length= sizeof(buffer);
        if ( target == GROUP_CLIENT_INDEX )
        {
            address = 0xCAFE;
            address_set(address);
            SEGGER_RTT_printf(0,"Sending to group address 0x%04x\n", address);
        }
        if ( simple_message_send(m_clients[target].model_handle, buffer, length, SIMPLE_MESSAGE_OPCODE_REQUEST) )
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Fail sending REQUEST\n");        
        }
    }
    
    void send_my_50_message (uint32_t target, char c) 
    {
        uint8_t buffer[20]="Message de 20 bytes";
        buffer[19]=(uint8_t)c;
        uint8_t length;
        uint16_t address;
        length= sizeof(buffer);
        if (simple_message_send(m_clients[target].model_handle, buffer, length, SIMPLE_MESSAGE_OPCODE_REQUEST) )
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Fail sending REQUEST\n");        
        }
        nrf_delay_us(1000000);
    }
    
    
    static void button_event_handler(uint32_t button_number)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Button %u pressed\n", button_number);
        if (m_configured_devices == 0)
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_WARN, "No devices provisioned\n");
            return;
        }
        else if (m_configured_devices <= button_number && button_number != BUTTON_NUMBER_GROUP)
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_WARN, "Device %u not provisioned yet.\n", button_number);
            return;
        }
    
        uint32_t status = NRF_SUCCESS;
        switch (button_number)
        {
            case 0:
            case 1:
            case 2:
                /* Invert LED. */
                //status = simple_on_off_client_set(&m_clients[button_number],
                //!hal_led_pin_get(BSP_LED_0 + button_number));
                //send_my_message(button_number);
                for ( uint8_t i=0 ; i < 5 ; i++)
                {
                    nrf_delay_us(1000000);
                    send_my_50_message(button_number,i);
                }
                break;
            case 3:
                /* Group message: invert all LEDs. */
                //status = simple_on_off_client_set_unreliable(&m_clients[GROUP_CLIENT_INDEX],
                //                                             !hal_led_pin_get(BSP_LED_0 + button_number), 3);
                send_my_message(button_number);
                break;
            default:
                break;
    
        }
    
        if (status == NRF_ERROR_INVALID_STATE ||
            status == NRF_ERROR_NO_MEM ||
            status == NRF_ERROR_BUSY)
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Cannot send. Device is busy.\n");
            hal_led_blink_ms(LEDS_MASK, 50, 4);
        }
        else
        {
            ERROR_CHECK(status);
        }
    }
    
    /*****************************************************************************
     * Event callbacks from the provisioner
     *****************************************************************************/
    
    void provisioner_config_successful_cb(void)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Configuration of device %u successful\n", m_configured_devices);
    
        /* Set publish address for the client to the corresponding server. */
        ERROR_CHECK(access_model_publish_address_set(m_clients[m_configured_devices].model_handle,
                                                     m_server_handles[m_configured_devices]));
        access_flash_config_store();
    
        hal_led_pin_set(BSP_LED_0 + m_configured_devices, false);
        m_configured_devices++;
    
        if (m_configured_devices < SERVER_COUNT)
        {
            provisioner_wait_for_unprov(UNPROV_START_ADDRESS + m_provisioned_devices);
            hal_led_pin_set(BSP_LED_0 + m_configured_devices, true);
        }
        else
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "All servers provisioned\n");
            hal_led_blink_ms(LEDS_MASK, 100, 4);
        }
    }
    
    void provisioner_config_failed_cb(void)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Configuration of device %u failed\n", m_configured_devices);
    
        /* Delete key and address. */
        ERROR_CHECK(dsm_address_publish_remove(m_server_handles[m_configured_devices]));
        ERROR_CHECK(dsm_devkey_delete(m_devkey_handles[m_configured_devices]));
        provisioner_wait_for_unprov(UNPROV_START_ADDRESS + m_provisioned_devices);
    }
    
    void provisioner_prov_complete_cb(const nrf_mesh_prov_evt_complete_t * p_prov_data)
    {
        /* We should not get here if all servers are provisioned. */
        NRF_MESH_ASSERT(m_configured_devices < SERVER_COUNT);
    
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Provisioning complete. Adding address 0x%04x.\n", p_prov_data->address);
    
        /* Add to local storage. */
        ERROR_CHECK(dsm_address_publish_add(p_prov_data->address, &m_server_handles[m_provisioned_devices]));
        ERROR_CHECK(dsm_devkey_add(p_prov_data->address, m_netkey_handle, p_prov_data->p_devkey, &m_devkey_handles[m_provisioned_devices]));
    
        /* Bind the device key to the configuration server and set the new node as the active server. */
        ERROR_CHECK(config_client_server_bind(m_devkey_handles[m_provisioned_devices]));
        ERROR_CHECK(config_client_server_set(m_devkey_handles[m_provisioned_devices],
                                             m_server_handles[m_provisioned_devices]));
    
        m_provisioned_devices++;
    
        /* Move on to the configuration step. */
        provisioner_configure(UNPROV_START_ADDRESS + m_configured_devices);
    }
    
    static void rtt_input_handler(int key)
    {
        if (key >= '0' && key <= '3')
        {
            uint32_t button_number = key - '0';
            button_event_handler(button_number);
        }
    }
    
    int main(void)
    {
        __LOG_INIT(LOG_SRC_APP | LOG_SRC_ACCESS, LOG_LEVEL_DBG1, LOG_CALLBACK_DEFAULT);
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- BLE Mesh Light Switch Client Demo -----\n");
    
        hal_leds_init();
        ERROR_CHECK(hal_buttons_init(button_event_handler));
    
        /* Set the first LED */
        hal_led_pin_set(BSP_LED_0, true);
        mesh_core_setup();
        access_setup();
        rtt_input_enable(rtt_input_handler, RTT_INPUT_POLL_PERIOD_MS);
    
        while (true)
        {
            (void)sd_app_evt_wait();
        }
    }
    

Children
No Data
Related