Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

No memory (error 4) on nrf_sdh.c:391

Hi. Currently I am been getting NRF_ERROR_NO_MEM on nrf_sdh.c:391. I am using the nrf5 SDK 17.0.2 and the nrf5 SDK for Mesh, working primarily on the nrf52840 DK.

So currently in my program there are many moving parts, which I suspect when put together may be causing this issue, however, I have been struggling to figure out why this error happens.

A little background on the things my program uses: Currently in my program, it is using a limited subset of the Mesh SDK since I only need the Mesh DFU functionality from it as I described here in a previous ticket:  Use Mesh DFU but on a non-mesh BLE example. To achieve this, I only initialized a subset of the mesh SDK functions (I will explain in further detail later in my post what I did when I get to showing my code). Additionally, the program is both a BLE Central and BLE peripheral. I also use the app_scheduler library that I guess kind of ties all this together. 

Here is the beginning part of my code that I am able to show:

#define APP_SCHED_EVENT_SIZE 12
#define APP_SCHED_QUEUE_SIZE 32

void ble_stack_init(void) {
    ERROR_CHECK(nrf_sdh_enable_request());

    // Configure the BLE stack using the default settings.
    // Fetch the start address of the application RAM.
    uint32_t ram_start = 0;
    ERROR_CHECK(nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start));

    // Enable BLE stack.
    ERROR_CHECK(nrf_sdh_ble_enable(&ram_start));

    // Register a handler for BLE events.
    NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);

    NRF_SDH_SOC_OBSERVER(mesh_observer, NRF_SDH_BLE_STACK_OBSERVER_PRIO, on_sd_evt, NULL);
}

void gap_params_init(void) {
    ble_gap_conn_params_t gap_conn_params;
    ble_gap_conn_sec_mode_t sec_mode;

    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);

    ERROR_CHECK(sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *) DEVICE_NAME, strlen(DEVICE_NAME)));

    memset(&gap_conn_params, 0, sizeof(gap_conn_params));

    gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
    gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
    gap_conn_params.slave_latency     = SLAVE_LATENCY;
    gap_conn_params.conn_sup_timeout  = CONN_SUP_TIMEOUT;

    ERROR_CHECK(sd_ble_gap_ppcp_set(&gap_conn_params));
}

void gatt_init(void) {
    ERROR_CHECK(nrf_ble_gatt_init(&m_gatt, gatt_evt_handler));
    ERROR_CHECK(nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE));
}

void conn_params_init(void) {
    ble_conn_params_init_t cp_init;

    memset(&cp_init, 0, sizeof(cp_init));

    cp_init.p_conn_params = NULL;
    cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
    cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY;
    cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT;
    cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
    cp_init.disconnect_on_fail = false;
    cp_init.evt_handler = on_conn_params_evt;
    cp_init.error_handler = conn_params_error_handler;

    ERROR_CHECK(ble_conn_params_init(&cp_init));
}


static nrf_mesh_init_params_t mesh_init_params = {
    .irq_priority       = NRF_MESH_IRQ_PRIORITY_THREAD,
    .lfclksrc           = DEV_BOARD_LF_CLK_CFG,
};

static void initialize(void) {
    ERROR_CHECK(app_timer_init());
    
    __LOG_INIT(LOG_SRC_APP | LOG_SRC_MEM_MANAGER | LOG_SRC_DFU, LOG_LEVEL_INFO, LOG_CALLBACK_DEFAULT);
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "-------- DevID %08X %08X --------\n", NRF_FICR->DEVICEID[1], NRF_FICR->DEVICEID[0]);
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "------- DevAddr %08X %08X -------\n", NRF_FICR->DEVICEADDR[1], NRF_FICR->DEVICEADDR[0]);

    ble_stack_init();
    APP_SCHED_INIT(APP_SCHED_EVENT_SIZE, APP_SCHED_QUEUE_SIZE);
    gap_params_init();
    gatt_init();
    ble_central_manager_init(); //Initializes BLE services (I use BLE_NUS service) and advertising module (ble_advertising_init())
    ble_peripheral_manager_init(); //Initializes the DB discovery module (ble_db_discovery_init()) and the scanner (nrf_ble_scan_init())
    conn_params_init();
    uarte_link_init(uart_data_handle);

    ERROR_CHECK(nrf_mesh_init(&mesh_init_params)); //I call this directly since I don't need the Access layer or foundation models
    dfu_handler_init(); //This function is wrapper for all the code in the Mesh SDK's DFU example
}

static void start(void) {
    rtt_input_enable(rtt_debug_util_handler, RTT_INPUT_POLL_PERIOD_MS);
    ble_peripheral_manager_start(); //begins advertising (ble_advertising_start(), fast advertising)
    ble_central_manager_start(); //begins scanning for the desired peripheral to connect (nrf_ble_scan_start())
    
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, m_usage_string);

    ERROR_CHECK(nrf_mesh_enable());
}

int main(void) {
#if CONFIG_JLINK_MONITOR_ENABLED
    NVIC_SetPriority(DebugMonitor_IRQn, APP_IRQ_PRIORITY_LOW_MID); //for monitor mode debugging
#endif
    initialize();
    start();

    for (;;) {
        app_sched_execute();
    	bool mesh_process_done = nrf_mesh_process();
    	if (mesh_process_done) {
    	    sd_app_evt_wait();
    	}
    }
}

I call nrf_mesh_init() directly since I only need the DFU portion of the Mesh SDK, I don't think it causes issues with DFU as I tested it on a minimal example from the mesh SDK where I called nrf_mesh_init() directly and did a successful DFU. 

So far what I am found is that, if I comment out either one of the following functions, the NRF_ERROR_NO_MEM on nrf_sdh.c:391 is gone:
- ble_central_manager_start(); (which is just a wrapper that calls nrf_ble_scan_start())

- or nrf_mesh_enable(); (if I did deeper further into this function, I can comment out bearer_event_flag_set(m_mesh_be_flag))

However, for obvious reasons, the BLE Central functionality and the Mesh DFU functionality are crucial parts of the program. Is there a reason why this NRF_ERROR_NO_MEM on nrf_sdh.c:391 happens when I use the BLE Central scanning, Mesh stack, and app_scheduler together? I would really like to continue using these three components together.

  • Hi

    The nRF Mesh SDK is pretty large, and combining it with both DFU and a BLE central scanning + a few other peripherals/features I think will push even the nRF52840 to its limits. Are you able to see how much of the flash/RAM your application uses when you build it? The error code is seems to be returning from the app_sched_event_put() function that puts an event into the event queue for further processing. I imagine (since it goes away if you remove one of the other features in your project) that this could be caused by the nRF52840 actually being filled in Flash/RAM. Can you set a check to make sure that the app_sched_event_put() returns successfully when either the Mesh_enable() or central manager() function is gone?

    Best regards,
    Simon

  • Thank you for your reply

    I don't think size is a problem in this case. Currently with gcc-level 0 (no optimizations at all) and full debugging support, the Flash used by the application is 305.1KB. RAM used 55.8KB with my current APP_SCHED_QUEUE_SIZE of 32. I find that even if I increase my APP_SCHED_QUEUE_SIZE to something really large but still fits in my ram, like 4096, I will still get the NO_MEM error in the same line as long as both the nrf_scan_start() (wrapped by central_manager_start()) and nrf_mesh_enable both execute. In any case, I think this is a good reason to suspect that the issue lies elsewhere. 

    I can confirm that the program runs fine without crashing when either one of the two are commented out. But since the program only uses 305.1 KB and 55.8 KB RAM, i don't think memory is the issue despite the error, especially because adjusting the APP_SCHED_QUEUE_SIZE to a very large doesn't seem to help with the problem at all. 

    Is it possible that it could be a problem with just recieving way too many interrupts due to a bug or phenomenon of some sort when combining the two that quickly overwhelms the scheduler queue instantly? In the meantime i think I will try to test out a minimal example just involving a BLE central and mesh code and see how that goes

  • Ok so i just tried to put together the BLE_BLINKY_CENTRAL example from the nrf5 sdk together with the Mesh DFU no serial example (that is modified to use the app_scheduler), and failed and got the same issue. I probably should've tried to do this before creating this ticket, my apologies.

    Anyways, when I tried to put to together this minimal example, I still get the same "NO MEM" error in the exact same place. Since i cannot get even a minimal example to run, my question now becomes simpler: 

    How do you integrate BLE Central that uses the nrf_scan module together with Mesh in the same program? 

    Here is the code from my attempt to integrate the two examples:

    /* Copyright (c) 2010 - 2020, 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 <boards.h>
    #include "nrf_mesh_events.h"
    #include "log.h"
    #include "nrf_mesh_dfu.h"
    #include "nrf_mesh.h"
    #include "mesh_app_utils.h"
    #include "mesh_stack.h"
    #include "ble_softdevice_support.h"
    #include "mesh_provisionee.h"
    #include "nrf_mesh_config_examples.h"
    #include "simple_hal.h"
    #include "app_timer.h"
    #include "example_common.h"
    #include "mesh_app_utils.h"
    #include "nrf_mesh_configure.h"
    #include "app_util.h"
    #include "nrf_mesh_serial.h"
    #include "app_scheduler.h"
    #include "rtt_input.h"
    
    #include "ble.h"
    #include "ble_hci.h"
    #include "ble_conn_params.h"
    #include "ble_db_discovery.h"
    #include "ble_lbs_c.h"
    #include "nrf_ble_gatt.h"
    #include "nrf_ble_scan.h"
    #include "nrf_delay.h"
    /*****************************************************************************
     * Definitions
     *****************************************************************************/
    /* LED mask bit 0 (1,2,..) represents BSP_LED_0 (1,2,..) from boards.h */
    #define LEDS_MASK_DFU_RUNNING   (0x05)  /* BSP_LED_0 and BSP_LED_2 */
    #define LEDS_MASK_DFU_ENDED     (0x03)  /* BSP_LED_0 and BSP_LED_1 */
    
    #define SCAN_INTERVAL                   0x00A0                              /**< Determines scan interval in units of 0.625 millisecond. */
    #define SCAN_WINDOW                     0x0050                              /**< Determines scan window in units of 0.625 millisecond. */
    #define SCAN_DURATION                   0x0000                              /**< Timout when scanning. 0x0000 disables timeout. */
    
    #define MIN_CONNECTION_INTERVAL         MSEC_TO_UNITS(7.5, UNIT_1_25_MS)    /**< Determines minimum connection interval in milliseconds. */
    #define MAX_CONNECTION_INTERVAL         MSEC_TO_UNITS(30, UNIT_1_25_MS)     /**< Determines maximum connection interval in milliseconds. */
    #define SLAVE_LATENCY                   0                                   /**< Determines slave latency in terms of connection events. */
    #define SUPERVISION_TIMEOUT             MSEC_TO_UNITS(4000, UNIT_10_MS)     /**< Determines supervision time-out in units of 10 milliseconds. */
    
    #define LEDBUTTON_BUTTON_PIN            NRF_GPIO_PIN_MAP(1,6)               /**< Button that will write to the LED characteristic of the peer */
    #define LEDBUTTON_BUTTON_PIN2           NRF_GPIO_PIN_MAP(0,12)               /**< Button that will write to the LED characteristic of the peer */
    #define LEDBUTTON_BUTTON_PIN3           NRF_GPIO_PIN_MAP(0,13)               /**< Button that will write to the LED characteristic of the peer */
    
    #define BUTTON_DETECTION_DELAY          APP_TIMER_TICKS(50)                 /**< Delay from a GPIOTE event until a button is reported as pushed (in number of timer ticks). */
    
    #define APP_BLE_CONN_CFG_TAG            1                                   /**< A tag identifying the SoftDevice BLE configuration. */
    #define APP_BLE_OBSERVER_PRIO           3                                   /**< Application's BLE observer priority. You shouldn't need to modify this value. */
    
    NRF_BLE_SCAN_DEF(m_scan);                                       /**< Scanning module instance. */
    BLE_LBS_C_DEF(m_ble_lbs_c);                                     /**< Main structure used by the LBS client module. */
    NRF_BLE_GATT_DEF(m_gatt);                                       /**< GATT module instance. */
    BLE_DB_DISCOVERY_DEF(m_db_disc);                                /**< DB discovery module instance. */
    NRF_BLE_GQ_DEF(m_ble_gatt_queue,                                /**< BLE GATT Queue instance. */
                   NRF_SDH_BLE_CENTRAL_LINK_COUNT,
                   NRF_BLE_GQ_QUEUE_SIZE);
    
    
    static char const m_target_periph_name[] = "79-1000-2204034";     /**< Name of the device we try to connect to. This name is searched in the scan report data*/
    
    /*****************************************************************************
     * Forward declaration of static functions
     *****************************************************************************/
    
    
    /*****************************************************************************
     * Static variables
     *****************************************************************************/
    static nrf_mesh_evt_handler_t m_evt_handler;
    static bool m_device_provisioned;
    
    static bool fw_updated_event_is_for_me(const nrf_mesh_evt_dfu_t * p_evt)
    {
        switch (p_evt->fw_outdated.transfer.dfu_type)
        {
            case NRF_MESH_DFU_TYPE_APPLICATION:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "DFU type Application\n");
                return (p_evt->fw_outdated.current.application.app_id == p_evt->fw_outdated.transfer.id.application.app_id &&
                        p_evt->fw_outdated.current.application.company_id == p_evt->fw_outdated.transfer.id.application.company_id &&
                        p_evt->fw_outdated.current.application.app_version < p_evt->fw_outdated.transfer.id.application.app_version);
    
            case NRF_MESH_DFU_TYPE_BOOTLOADER:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "DFU type Bootloader\n");
                return (p_evt->fw_outdated.current.bootloader.bl_id == p_evt->fw_outdated.transfer.id.bootloader.bl_id &&
                        p_evt->fw_outdated.current.bootloader.bl_version < p_evt->fw_outdated.transfer.id.bootloader.bl_version);
    
            case NRF_MESH_DFU_TYPE_SOFTDEVICE:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "DFU type Softdevice\n");
                return false;
    
            default:
                return false;
        }
    }
    
    static const uint32_t * optimal_bank_address(void)
    {
        /* The incoming transfer has to fit on both sides of the bank address: First it needs to fit
         * above the bank address when we receive it, then it needs to fit below the bank address when
         * we install it. We want to put the bank address in the middle of the available application
         * code area, to maximize the potential transfer size we can accept. */
        const uint32_t * p_start;
        uint32_t dummy;
        ERROR_CHECK(mesh_stack_persistence_flash_usage(&p_start, &dummy));
    
        uint32_t middle_of_app_area = (CODE_START + (intptr_t) p_start) / 2;
    
        /* The bank can't start in the middle of the application code, and should be page aligned: */
        return (const uint32_t *) ALIGN_VAL(MAX(middle_of_app_area, CODE_END), PAGE_SIZE);
    }
    
    static void mesh_evt_handler(const nrf_mesh_evt_t* p_evt)
    {
        switch (p_evt->type)
        {
            case NRF_MESH_EVT_DFU_FIRMWARE_OUTDATED:
            case NRF_MESH_EVT_DFU_FIRMWARE_OUTDATED_NO_AUTH:
                if (fw_updated_event_is_for_me(&p_evt->params.dfu))
                {
                    const uint32_t * p_bank = optimal_bank_address();
                    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Requesting DFU transfer with bank at 0x%p\n", p_bank);
    
                    ERROR_CHECK(nrf_mesh_dfu_request(p_evt->params.dfu.fw_outdated.transfer.dfu_type,
                                                     &p_evt->params.dfu.fw_outdated.transfer.id,
                                                     p_bank));
                    hal_led_mask_set(HAL_LED_MASK, false); /* Turn off all LEDs */
                }
                elsep
                {
                    /**
                     * While preparing for the start of the DFU process, the DFU module
                     * will notify about any other ongoing DFU transfers by sending
                     * @ref NRF_MESH_EVT_DFU_FIRMWARE_OUTDATED_NO_AUTH or
                     * @ref NRF_MESH_EVT_DFU_FIRMWARE_OUTDATED.
                     *
                     * Check the current DFU state to avoid reverting the target state
                     * to the relay state.
                     */
                    nrf_mesh_dfu_transfer_state_t state;
                    uint32_t error_code = nrf_mesh_dfu_state_get(&state);
                    if (error_code == NRF_SUCCESS && (state.state == NRF_MESH_DFU_STATE_INITIALIZED ||
                                                      state.state == NRF_MESH_DFU_STATE_FIND_FWID ||
                                                      state.state == NRF_MESH_DFU_STATE_RELAY_CANDIDATE ||
                                                      state.state == NRF_MESH_DFU_STATE_RELAY))
                    {
                        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Starting relay\n");
                        ERROR_CHECK(nrf_mesh_dfu_relay(p_evt->params.dfu.fw_outdated.transfer.dfu_type,
                                                        &p_evt->params.dfu.fw_outdated.transfer.id));
                    }
                }
                break;
    
            case NRF_MESH_EVT_DFU_START:
                hal_led_mask_set(LEDS_MASK_DFU_RUNNING, true);
                break;
    
            case NRF_MESH_EVT_DFU_END:
                hal_led_mask_set(HAL_LED_MASK, false); /* Turn off all LEDs */
                hal_led_mask_set(LEDS_MASK_DFU_ENDED, true);
                break;
    
            case NRF_MESH_EVT_DFU_BANK_AVAILABLE:
                hal_led_mask_set(HAL_LED_MASK, false); /* Turn off all LEDs */
                ERROR_CHECK(nrf_mesh_dfu_bank_flash(p_evt->params.dfu.bank.transfer.dfu_type));
                break;
    
            default:
                break;
    
        }
    }
    
    /**@brief Function to handle asserts in the SoftDevice.
     *
     * @details This function will be called in case of an assert in the SoftDevice.
     *
     * @warning This handler is an example only and does not fit a final product. You need to analyze
     *          how your product is supposed to react in case of Assert.
     * @warning On assert from the SoftDevice, the system can only recover on reset.
     *
     * @param[in] line_num     Line number of the failing ASSERT call.
     * @param[in] p_file_name  File name of the failing ASSERT call.
     */
    void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
    {
        app_error_handler(0xDEADBEEF, line_num, p_file_name);
    }
    
    static void draw_ui(char * top, char * bottom) {
        static char lcd_buf_top[27];
        static char lcd_buf_bot[27];
    
        if (top != NULL) sprintf(lcd_buf_top, top);
        if (bottom != NULL) sprintf(lcd_buf_bot, bottom);
    }
    
    
    
    /**@brief Function for handling the LED Button Service client errors.
     *
     * @param[in]   nrf_error   Error code containing information about what went wrong.
     */
    static void lbs_error_handler(uint32_t nrf_error)
    {
        //APP_ERROR_HANDLER(nrf_error);
    }
    
    /**@brief Function to start scanning.
     */
    static void scan_start(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_ble_scan_start(&m_scan);
        APP_ERROR_CHECK(err_code);
    }
    
    typedef struct __attribute((packed)) {
        uint8_t first_byte;
        uint8_t opcode;
        uint8_t len_of_rest;
        uint8_t zero_padd;
        float float_data;
        uint16_t terminator;
    } data_format_t;
    
    /**@brief Handles events coming from the LED Button central module.
     */
    static void lbs_c_evt_handler(ble_lbs_c_t * p_lbs_c, ble_lbs_c_evt_t * p_lbs_c_evt)
    {
        char buff[20] = {0};
        data_format_t * data_in;
    
        switch (p_lbs_c_evt->evt_type)
        {
            case BLE_LBS_C_EVT_DISCOVERY_COMPLETE:
            {
                ret_code_t err_code;
    
                err_code = ble_lbs_c_handles_assign(&m_ble_lbs_c,
                                                    p_lbs_c_evt->conn_handle,
                                                    &p_lbs_c_evt->params.peer_db);
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "LED Button service discovered on conn_handle 0x%x.\n", p_lbs_c_evt->conn_handle);
    
    
                // LED Button service discovered. Enable notification of Button.
                err_code = ble_lbs_c_button_notif_enable(p_lbs_c);
                APP_ERROR_CHECK(err_code);
            } break; // BLE_LBS_C_EVT_DISCOVERY_COMPLETE
    
            case BLE_LBS_C_EVT_BUTTON_NOTIFICATION:
                //stuff
                break; // BLE_LBS_C_EVT_BUTTON_NOTIFICATION
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    
    /**@brief Function for handling BLE events.
     *
     * @param[in]   p_ble_evt   Bluetooth stack event.
     * @param[in]   p_context   Unused.
     */
    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ret_code_t err_code;
    
        // For readability.
        ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
    
        switch (p_ble_evt->header.evt_id)
        {
            // Upon connection, check which peripheral has connected (HR or RSC), initiate DB
            // discovery, update LEDs status and resume scanning if necessary. */
            case BLE_GAP_EVT_CONNECTED:
            {
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Connected.");
                err_code = ble_lbs_c_handles_assign(&m_ble_lbs_c, p_gap_evt->conn_handle, NULL);
                APP_ERROR_CHECK(err_code);
    
                err_code = ble_db_discovery_start(&m_db_disc, p_gap_evt->conn_handle);
                APP_ERROR_CHECK(err_code);
    
            } break;
    
            // Upon disconnection, reset the connection handle of the peer which disconnected, update
            // the LEDs status and start scanning again.
            case BLE_GAP_EVT_DISCONNECTED:
            {
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Disconnected.\n");
                scan_start();
            } break;
    
            case BLE_GAP_EVT_TIMEOUT:
            {
                // We have not specified a timeout for scanning, so only connection attemps can timeout.
                if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN)
                {
                    //NRF_LOG_DEBUG("Connection request timed out.");
                }
            } break;
    
            case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
            {
                // Accept parameters requested by peer.
                err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle,
                                            &p_gap_evt->params.conn_param_update_request.conn_params);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
            {
                //NRF_LOG_DEBUG("PHY update request.");
                ble_gap_phys_t const phys =
                {
                    .rx_phys = BLE_GAP_PHY_AUTO,
                    .tx_phys = BLE_GAP_PHY_AUTO,
                };
                err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GATTC_EVT_TIMEOUT:
            {
                // Disconnect on GATT Client timeout event.
                //NRF_LOG_DEBUG("GATT Client Timeout.");
                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GATTS_EVT_TIMEOUT:
            {
                // Disconnect on GATT Server timeout event.
                //NRF_LOG_DEBUG("GATT Server Timeout.");
                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);
            } break;
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    
    /**@brief LED Button client initialization.
     */
    static void lbs_c_init(void)
    {
        ret_code_t       err_code;
        ble_lbs_c_init_t lbs_c_init_obj;
    
        lbs_c_init_obj.evt_handler   = lbs_c_evt_handler;
        lbs_c_init_obj.p_gatt_queue  = &m_ble_gatt_queue;
        lbs_c_init_obj.error_handler = lbs_error_handler;
    
        err_code = ble_lbs_c_init(&m_ble_lbs_c, &lbs_c_init_obj);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling Scaning events.
     *
     * @param[in]   p_scan_evt   Scanning event.
     */
    static void scan_evt_handler(scan_evt_t const * p_scan_evt)
    {
        ret_code_t err_code;
    
        switch(p_scan_evt->scan_evt_id)
        {
            case NRF_BLE_SCAN_EVT_CONNECTING_ERROR:
                err_code = p_scan_evt->params.connecting_err.err_code;
                APP_ERROR_CHECK(err_code);
                break;
            default:
              break;
        }
    }
    
    
    /**@brief Function for handling database discovery events.
     *
     * @details This function is callback function to handle events from the database discovery module.
     *          Depending on the UUIDs that are discovered, this function should forward the events
     *          to their respective services.
     *
     * @param[in] p_event  Pointer to the database discovery event.
     */
    static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
    {
        ble_lbs_on_db_disc_evt(&m_ble_lbs_c, p_evt);
    }
    
    
    /**@brief Database discovery initialization.
     */
    static void db_discovery_init(void)
    {
        ble_db_discovery_init_t db_init;
    
        memset(&db_init, 0, sizeof(db_init));
    
        db_init.evt_handler  = db_disc_handler;
        db_init.p_gatt_queue = &m_ble_gatt_queue;
    
        ret_code_t err_code = ble_db_discovery_init(&db_init);
        APP_ERROR_CHECK(err_code);
    }
    
    static void scan_init(void)
    {
        ret_code_t          err_code;
        nrf_ble_scan_init_t init_scan;
    
        memset(&init_scan, 0, sizeof(init_scan));
    
        init_scan.connect_if_match = true;
        init_scan.conn_cfg_tag     = APP_BLE_CONN_CFG_TAG;
    
        err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler);
        APP_ERROR_CHECK(err_code);
    
        // Setting filters for scanning.
        err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_NAME_FILTER, false);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_NAME_FILTER, m_target_periph_name);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for initializing the GATT module.
     */
    static void gatt_init(void)
    {
        ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    
    
    static void rtt_evt_handler(int key) {
        uint32_t status;
    
        switch (key) {
            case '1':
    	        //read led service
            case '2':
                break;
    
            default:
                break;
        }
    }
    
    static void node_reset(void)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- Node reset  -----\n");
        hal_led_blink_ms(HAL_LED_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_RESET);
        /* This function may return if there are ongoing flash operations. */
        mesh_stack_device_reset();
    }
    
    static void config_server_evt_cb(const config_server_evt_t * p_evt)
    {
        if (p_evt->type == CONFIG_SERVER_EVT_NODE_RESET)
        {
            node_reset();
        }
    }
    
    static void mesh_init(void)
    {
        nrf_mesh_init_params_t init_params =
        {
            .irq_priority       = NRF_MESH_IRQ_PRIORITY_THREAD,
            .lfclksrc           = DEV_BOARD_LF_CLK_CFG,
    	.p_uuid = NULL,
    	.relay_cb = NULL
        };
    
        uint32_t status = nrf_mesh_init(&init_params);
        switch (status)
        {
            case NRF_ERROR_INVALID_DATA:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Data in the persistent memory was corrupted. Device starts as unprovisioned.\n");
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Reboot device before starting of the provisioning process.\n");
                break;
            case NRF_SUCCESS:
                break;
            default:
                ERROR_CHECK(status);
        }
    
    #if NRF_MESH_SERIAL_ENABLE
        ERROR_CHECK(nrf_mesh_serial_init(NULL));
    #endif
    
        m_evt_handler.evt_cb = mesh_evt_handler;
        nrf_mesh_evt_handler_add(&m_evt_handler);
    }
    
    static void initialize(void)
    {
        ERROR_CHECK(app_timer_init());
        hal_leds_init();
    
        __LOG_INIT(LOG_MSK_DEFAULT | LOG_SRC_DFU | LOG_SRC_APP | LOG_SRC_SERIAL, LOG_LEVEL_INFO, log_callback_rtt);
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- Bluetooth Mesh DFU Example -----\n");
        ble_stack_init();
    
        APP_SCHED_INIT(8, 32);
        scan_init();
        gatt_init();
        db_discovery_init();
        lbs_c_init();
    
        mesh_init();
    
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Initialization complete!\n");
    }
    
    static void start(void)
    {
    #if NRF_MESH_SERIAL_ENABLE
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Enabling serial interface...\n");
        ERROR_CHECK(nrf_mesh_serial_enable());
    #endif
        rtt_input_enable(rtt_evt_handler, RTT_INPUT_POLL_PERIOD_MS);
    
        mesh_app_uuid_print(nrf_mesh_configure_device_uuid_get());
        scan_start();
    
        ERROR_CHECK(nrf_mesh_enable());
    
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "DFU example started!\n");
    }
    
    int main(void)
    {
        initialize();
        start();
    
        for (;;)
        {
            app_sched_execute();
    	bool done = nrf_mesh_process();
    	if (done)
    	{
    	    sd_app_evt_wait();
    	}
        }
    }
    

  • Hi

    We're somewhat short of staff, so delayed replies must be expected I'm afraid. Thank you for your patience. After discussing this with a colleague, we see that the issue might be that both the BT Mesh stack and the SoftDevice tries to do scanning at the same time. Not sure why this trigs a NO MEM error though to be honest. 

    In order to share the scan packets for the BLE scanner and Bluetooth Mesh RX you need to call the nrf_mesh_rx_cb_set after nrf_mesh_init(). But please note that running the SoftDevice in parallel with the Mesh stack will require timesharing between the BLE and Mesh stack, which will result in worse performance for both stacks. The callback will let both stacks get access to the radio in RX.

    Best regards,

    Simon

  • Thank you, that makes sense. Using this I am able to see advertising packets, however, there is still the problem of not being able to view the scan response data and how do you actually connect to the advertisements? 

    In the infocenter I was just reading this: https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.meshsdk.v5.0.0%2Fmd_doc_user_guide_integrating_mesh_nrf5_sdk.html&cp=8_2_2_7

    and here it says that "If general passive BLE scanning is required (for listening for beacons or other third party activity), hook into the Bluetooth mesh scanner by setting an RX callback with the nrf_mesh_rx_cb_set function. If your application requires active scanning or needs to initiate a connection, the scan parameters should be set as conservatively as possible."

    How would an implementation of active scanning or initiating a connection from the callback nrf_mesh_rx_cb_set look like, since the infocenter did not mention anything about how to do such an implementation and there are no examples

Related