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

How to update advertisement packet SDK 15.0.0 ?

Dear all,

I am trying to develop an application that reads data from a sensor (accelerometer) and I want to be able to update the advertisement packet with the measurement I obtain from it.

So far I am able to read the values from the sensor. Using this example as a basis I can transmit a single value, but I am unable to update the content of the package in order to be able to read the right value. Is there any idea, how I can do this update?

I am using SDK 15.0.0.0. From what I have seen in the forum there is no straight forward way to do this, but I wonder, if someone has the same issue and if it is possible to share some sample code with me.

Kind regards

Parents
  • HI,

    You can refer to my example at https://github.com/jimmywong2003/nrf5-modify-device-parameter-through-host/blob/modify_non_connectable_advertising/ble_app_change_advertising_example/main.c

    I hardcode the enc_advdata (advertising data) and set the adv data with pointer.

    and then update the battery info (fill up the 1st byte of advdata) in the ADV payload.

            m_adv_data.adv_data.p_data = m_hardcode_enc_advdata;
            m_adv_data.adv_data.len    = 0x1F; // hardcode to 31 bytes
    
            err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &m_adv_params);
            APP_ERROR_CHECK(err_code);

    void saadc_event_handler(nrf_drv_saadc_evt_t const * p_event)
    {
            if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
            {
                    nrf_saadc_value_t adc_result;
                    uint16_t batt_lvl_in_milli_volts;
                    // uint8_t percentage_batt_lvl;
                    uint32_t err_code;
    
                    adc_result = p_event->data.done.p_buffer[0];
    
                    err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, 1);
                    APP_ERROR_CHECK(err_code);
    
                    batt_lvl_in_milli_volts = ADC_RESULT_IN_MILLI_VOLTS(adc_result) +
                                              DIODE_FWD_VOLT_DROP_MILLIVOLTS;
                    m_percentage_batt_lvl = battery_level_in_percent(batt_lvl_in_milli_volts);
    
    #if defined(USE_THINGY_ADVERTISING_PAYLOAD)
                    m_hardcode_enc_advdata[ADV_PAYLOAD_WITH_BATTERY]    = m_percentage_batt_lvl;
    #endif

  • Hi there Jimmy.

    I am not sure how exactly I can incorporate your code in mine.

    What I have so far is this:

    static void advertising_init(void)
    {
        ret_code_t             err_code;
        memset(&init, 0, sizeof(init));
    
        ble_advdata_manuf_data_t                  manuf_data; //Variable to hold manufacturer specific data
        uint8_t data[]                            = "SomeDa"; //Our data to advertise
        manuf_data.company_identifier             =  0x0059; //Nordics company ID
        manuf_data.data.p_data                    = data;
        manuf_data.data.size                      = sizeof(data);
        init.advdata.p_manuf_specific_data        = &manuf_data;
    
        int8_t tx_power                   = -56;// Set Power Level
        init.advdata.p_tx_power_level = &tx_power;
    
        init.advdata.name_type = BLE_ADVDATA_FULL_NAME; // Use a shortened name
        init.advdata.short_name_len = 6; // Advertise only first 6 letters of name
        init.advdata.flags                   = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
        init.advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
        init.advdata.uuids_complete.p_uuids  = m_adv_uuids;
    
        // Prepare the scan response manufacturer specific data packet
        ble_advdata_manuf_data_t  manuf_data_response;
        uint8_t                     data_response[] = "Many_bytes_of_data";
        manuf_data_response.company_identifier  = 0x0059;
        manuf_data_response.data.p_data         = data_response;
        manuf_data_response.data.size           = sizeof(data_response);
        init.srdata.name_type = BLE_ADVDATA_NO_NAME;
        init.srdata.p_manuf_specific_data = &manuf_data_response;
    
        init.config.ble_adv_fast_enabled  = true;
        init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
        init.config.ble_adv_fast_timeout  = APP_ADV_DURATION;
    
        init.evt_handler = on_adv_evt;
    
        err_code = ble_advertising_init(&m_advertising, &init);
        APP_ERROR_CHECK(err_code);
    
        ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
    }

    This is how I initialize my advertisement. At the moment I am not using any handler to read the data from the sensor, but I can write one.

    I am not sure I can incorporate your code to what I already have.

  • HI,

    Please try to read the full source code. if you don't know you can try on the board.

    Also, read the blog at https://jimmywongbluetooth.wordpress.com/2019/04/15/how-to-modify-the-device-information-through-ble-connection/.

    You should use the global variable instead of local variable (data).

    for example,

    static uint8_t m_hardcode_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX] =
    {
            0x02, 0x01, 0x04, //flags
            0x1B, 0xFF, 0x59,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
    };


    configure the advertising by using the pointer of this global variable.

    static void non_connectable_advertising_init(void)
    {
            uint32_t err_code;
            ble_advdata_t advdata;
            uint8_t flags = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED;
    
            ble_advdata_manuf_data_t manuf_specific_data;
            manuf_specific_data.company_identifier = APP_COMPANY_IDENTIFIER;
            ..
            ..
            m_adv_params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED;
            m_adv_params.p_peer_addr     = NULL;// Undirected advertisement.
            m_adv_params.filter_policy   = BLE_GAP_ADV_FP_ANY;
            m_adv_params.interval        = NON_CONNECTABLE_ADV_INTERVAL;
            m_adv_params.duration        = 0;   // Never time out.
    
            NRF_LOG_DEBUG("non_connectable_advertising_init");
    
            uint8_t length = m_ble_config->adv_payload.len;
    
            for (uint8_t i=0; i < length ; i++)
            {
                  m_hardcode_enc_advdata[ADV_PAYLOAD_WITH_BATTERY+1+i] = m_ble_config->adv_payload.data[i];
            }
            //memcpy(*m_hardcode_enc_advdata+ADV_PAYLOAD_WITH_BATTERY+1, m_ble_config->adv_payload.data, m_ble_config->adv_payload.len);
    
            // set the p_data to global variable pointer
            m_adv_data.adv_data.p_data = m_hardcode_enc_advdata;

    for example, I use the app_timer to regular read the battery value (through SAADC).

    void saadc_event_handler(nrf_drv_saadc_evt_t const * p_event)
    {
            if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
            {
                    nrf_saadc_value_t adc_result;
                    uint16_t batt_lvl_in_milli_volts;
                    // uint8_t percentage_batt_lvl;
                    uint32_t err_code = NRF_SUCCESS;
    
                    adc_result = p_event->data.done.p_buffer[0];
    
                    err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, 1);
                    APP_ERROR_CHECK(err_code);
    
                    batt_lvl_in_milli_volts = ADC_RESULT_IN_MILLI_VOLTS(adc_result) +
                                              DIODE_FWD_VOLT_DROP_MILLIVOLTS;
                    m_percentage_batt_lvl = battery_level_in_percent(batt_lvl_in_milli_volts);
    
    #if defined(USE_THINGY_ADVERTISING_PAYLOAD)
                    m_hardcode_enc_advdata[ADV_PAYLOAD_WITH_BATTERY]    = m_percentage_batt_lvl;
    #endif
                    NRF_LOG_INFO("Battery service value : %03d %%", m_percentage_batt_lvl);
    

  • I am using SDK 15.0.0. This is the error that I am getting trying to build the project.

  • HI,

    the example of the github is running at the SDK 15.3 (mentioned in the readme).

    You should port such part of code on the SDK 15.0 if you need. it is very straight forward and trivial.

Reply Children
  • Hi Jimmy. I took your code and I reduced to the minimum code necessary to simply update the advertisement package. I really want to thank you for your example and your code. I am posting the code bellow:

    /**
     * Copyright (c) 2014 - 2019, 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.
     *
     */
    /** @file
     *
     * @defgroup ble_sdk_uart_over_ble_main main.c
     * @{
     * @ingroup  ble_sdk_app_nus_eval
     * @brief    UART over BLE application main file.
     *
     * This file contains the source code for a sample application that uses the Nordic UART service.
     * This application uses the @ref srvlib_conn_params module.
     */
    
    #include "nordic_common.h"
    #include "nrf.h"
    #include "ble_advdata.h"
    #include "ble_advertising.h"
    #include "nrf_sdh_soc.h"
    #include "nrf_sdh_ble.h"
    #include "nrf_ble_qwr.h"
    
    #include "bsp_btn_ble.h"
    #include "nrf_pwr_mgmt.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #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. */
    #define APP_ADV_DURATION                0                                       /**< The advertising duration (180 seconds) in units of 10 milliseconds. */
    
    
    #define NON_CONNECTABLE_ADV_INTERVAL    MSEC_TO_UNITS(1000, UNIT_0_625_MS)  /**< The advertising interval for non-connectable advertisement (100 ms). This value can vary between 100ms to 10.24s). */
    
    #define APP_COMPANY_IDENTIFIER          0x0059                             /**< Company identifier for Nordic Semiconductor ASA. as per www.bluetooth.org. */
    
    static uint8_t m_hardcode_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX] =
    {
            0x02, 0x01, 0x04, //flags
            0x08, 0x09, 'G', 'i', 'a', 'n', 'n', 'i', 's',
            0x12, 0xFF, 0x59,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
    };
    
    #define INCREMENT_INTERVAL         APP_TIMER_TICKS(1000)                   /**< Increment interval (ticks). */
    
    #define DEAD_BEEF                       0xDEADBEEF                                  /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
    
    static ble_gap_adv_params_t m_adv_params;                                  /**< Parameters to be passed to the stack when starting advertising. */
    static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET;              /**< Advertising handle used to identify an advertising set. */
    
    NRF_BLE_QWR_DEF(m_qwr);                                                             /**< Context for the Queued Write module.*/
    BLE_ADVERTISING_DEF(m_advertising);                                                 /**< Advertising module instance. */
    
    
    static uint16_t m_conn_handle          = BLE_CONN_HANDLE_INVALID;                   /**< Handle of the current connection. */
    
    static uint8_t m_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX] =
    {
            02, 0x01, 0x04, //flags
            0x11, 0xFF, 0x59,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
            0x00, 0x01, 0x02, 0x03,
    };
    
    
    /**@brief Struct that contains pointers to the encoded advertising data. */
    static ble_gap_adv_data_t m_adv_data =
    {
            .adv_data =
            {
                    .p_data = m_enc_advdata,
                    .len    = BLE_GAP_ADV_SET_DATA_SIZE_MAX
            },
            .scan_rsp_data =
            {
                    .p_data = NULL,
                    .len    = 0
    
            }
    };
    
    /**@brief Function for initializing the timer module.
     */
    static void timers_init(void)
    {
            ret_code_t err_code = app_timer_init();
            APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for handling errors from the Connection Parameters module.
     *
     * @param[in] nrf_error  Error code containing information about what went wrong.
     */
    static void conn_params_error_handler(uint32_t nrf_error)
    {
            APP_ERROR_HANDLER(nrf_error);
    }
    
    /**@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)
    {
            uint32_t err_code;
    
            switch (p_ble_evt->header.evt_id)
            {
            case BLE_GAP_EVT_CONNECTED:
                    NRF_LOG_INFO("Connected");
                    err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
                    APP_ERROR_CHECK(err_code);
                    m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
                    err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
                    APP_ERROR_CHECK(err_code);
                    break;
    
            case BLE_GAP_EVT_DISCONNECTED:
                    NRF_LOG_INFO("Disconnected");
                    // LED indication will be changed when advertising starts.
                    m_conn_handle = BLE_CONN_HANDLE_INVALID;
                    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_GAP_EVT_SEC_PARAMS_REQUEST:
                    // Pairing not supported
                    err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);
                    APP_ERROR_CHECK(err_code);
                    break;
    
            case BLE_GATTS_EVT_SYS_ATTR_MISSING:
                    // No system attributes have been stored.
                    err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);
                    APP_ERROR_CHECK(err_code);
                    break;
    
            case BLE_GATTC_EVT_TIMEOUT:
                    // Disconnect on GATT Client timeout event.
                    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.
                    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 Function for the SoftDevice initialization.
     *
     * @details This function initializes the SoftDevice and the BLE event interrupt.
     */
    static void ble_stack_init(void)
    {
        ret_code_t err_code;
        err_code = nrf_sdh_enable_request();
        APP_ERROR_CHECK(err_code);
    
        // Configure the BLE stack using the default settings.
        // Fetch the start address of the application RAM.
        uint32_t ram_start = 0;
        err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
        APP_ERROR_CHECK(err_code);
    
        // Enable BLE stack.
        err_code = nrf_sdh_ble_enable(&ram_start);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for initializing the Advertising functionality.
     *
     * @details Encodes the required advertising data and passes it to the stack.
     *          Also builds a structure to be passed to the stack when starting advertising.
     */
    static void non_connectable_advertising_init(void)
    {
            uint32_t err_code;
            m_adv_params.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED;
            m_adv_params.interval        = NON_CONNECTABLE_ADV_INTERVAL;
            m_adv_params.duration        = APP_ADV_DURATION;
    
            NRF_LOG_DEBUG("non_connectable_advertising_init");
    
    
            m_adv_data.adv_data.p_data = m_hardcode_enc_advdata;
            m_adv_data.adv_data.len    = 0x1F; // hardcode to 31 bytes
    
            err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &m_adv_params);
            APP_ERROR_CHECK(err_code);
    
    }
    
    /**@brief Function for initializing the nrf log module.
     */
    static void log_init(void)
    {
            ret_code_t err_code = NRF_LOG_INIT(NULL);
            APP_ERROR_CHECK(err_code);
    
            NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    
    /**@brief Function for initializing power management.
     */
    static void power_management_init(void)
    {
            ret_code_t err_code;
            err_code = nrf_pwr_mgmt_init();
            APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for placing the application in low power state while waiting for events.
     */
    #define FPU_EXCEPTION_MASK 0x0000009F
    /**@brief Function for handling the idle state (main loop).
     *
     * @details If there is no pending log operation, then sleep until next the next event occurs.
     */
    static void idle_state_handle(void)
    {
            __set_FPSCR(__get_FPSCR()  & ~(FPU_EXCEPTION_MASK));
            (void) __get_FPSCR();
            NVIC_ClearPendingIRQ(FPU_IRQn);
    
            while(NRF_LOG_PROCESS());
            //UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
            nrf_pwr_mgmt_run();
    }
    
    /**@brief Function for starting advertising.
     */
    static void non_connect_advertising_start(void)
    {
            ret_code_t err_code;
    
            err_code = sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG);
            APP_ERROR_CHECK(err_code);
    
            err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
            APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for initializing Radio Notification Software Interrupts.
     */
    uint32_t radio_notification_init(uint32_t irq_priority, uint8_t notification_type, uint8_t notification_distance)
    {
        uint32_t err_code;
    
        err_code = sd_nvic_ClearPendingIRQ(SWI1_IRQn);
        if (err_code != NRF_SUCCESS)
        {
            return err_code;
        }
    
        err_code = sd_nvic_SetPriority(SWI1_IRQn, irq_priority);
        if (err_code != NRF_SUCCESS)
        {
            return err_code;
        }
    
        err_code = sd_nvic_EnableIRQ(SWI1_IRQn);
        if (err_code != NRF_SUCCESS)
        {
            return err_code;
        }
    
        // Configure the event
        return sd_radio_notification_cfg_set(notification_type, notification_distance);
    }
    
    /**@brief Software interrupt 1 IRQ Handler, handles radio notification interrupts.
     */
    void SWI1_IRQHandler(bool radio_evt)
    {
        if (radio_evt)
        {   
            nrf_gpio_pin_toggle(BSP_LED_2); //Toggle the status of the LED on each radio notification event
             m_hardcode_enc_advdata[30]++;
        }
    }
    
    
    /**@brief Application main function.
     */
    int main(void)
    {
            bool erase_bonds;
            bool connect_mode_enter = false;
            uint32_t err_code = NRF_SUCCESS;
            log_init();
            timers_init();
    
            //buttons_init();
            power_management_init();
            ble_stack_init();
            err_code = radio_notification_init(3, NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE, NRF_RADIO_NOTIFICATION_DISTANCE_NONE);
            //application_timer_start();
    
            non_connectable_advertising_init();
            non_connect_advertising_start();
    
            NRF_LOG_INFO("Non-Connected Advertising!");
    
    
            // Enter main loop.
            for (;;)
            {
                   idle_state_handle();
                   
            }
    }
    
    
    /**
     * @}
     */
    

    I hope this will clear things out for people. Also this code doesn't do the update job in SDK 15.0.0, but 15.3.0.

    Again thank you very much Jimmy.

Related