Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Stop button 1 entering DFU and button 4 disconnecting from BLE in custom buttonless DFU template

I am using the buttonless DFU template to run my own program which uses some of the buttons on the dev kit.  For some reason, my button configuration is being overlapped somewhere, making button 1 disconnect the dev kit from my mobile device after a long hold, and button 4 enter DFU mode alongside the normal functionality I want.  I never configured this myself and am wondering where else the button is being configured from.  Is there somewhere I should be looking within my project which will point me in the right direction?

#define DRAW_BUTTON                BSP_BUTTON_0    
#define STAT_BUTTON                BSP_BUTTON_1
#define PRESS_BUTTON               BSP_BUTTON_2  
#define ACCLRM_BUTTON              BSP_BUTTON_3  

static void button_event_handler(uint8_t pin_no, uint8_t button_action)
{
    ret_code_t err_code;

    switch (pin_no)
    {
        case DRAW_BUTTON:
            record_draw();                  
            break;
        case STAT_BUTTON:
            check_status();
            break;
        case ACCLRM_BUTTON:
            read_acclrm();
            break;
        case PRESS_BUTTON:
            read_pressure();
            break;
        default:
            APP_ERROR_HANDLER(pin_no);
            break;
    }
}

void buttons_init(void)
{
    ret_code_t err_code;

    //The array must be static because a pointer to it will be saved in the button handler module.
    static app_button_cfg_t buttons[] =
    {
        {BSP_BUTTON_0, false, BUTTON_PULL, button_event_handler},
        {BSP_BUTTON_1, false, BUTTON_PULL, button_event_handler},
        {BSP_BUTTON_2, false, BUTTON_PULL, button_event_handler},
        {BSP_BUTTON_3, false, BUTTON_PULL, button_event_handler},
    };

    err_code = app_button_init(buttons, ARRAY_SIZE(buttons),
                               BUTTON_DETECTION_DELAY);
    APP_ERROR_CHECK(err_code);

    err_code = app_button_enable();

    APP_ERROR_CHECK(err_code);
}
int main(void)
{
    bool       erase_bonds;
    ret_code_t err_code;

    log_init();

    // Initialize the async SVCI interface to bootloader before any interrupts are enabled.
    err_code = ble_dfu_buttonless_async_svci_init();
    APP_ERROR_CHECK(err_code);

    timers_init();
    power_management_init();
    //buttons_leds_init(&erase_bonds);
    buttons_init();
    ble_stack_init();
    peer_manager_init();
    gap_params_init();
    gatt_init();
    services_init();
    advertising_init();
    conn_params_init();

    NRF_LOG_INFO("Buttonless DFU Application started.");

    // Start execution.
    application_timers_start();
    rtc_config();
    twi_init();
    nrf_drv_rtc_disable(&rtc);
    nrf_drv_rtc_tick_disable(&rtc);
    advertising_start(erase_bonds);
    
    // Enter main loop.
    for (;;)
    {
        idle_state_handle();
    }
}

int main(void)
{
    bool       erase_bonds;
    ret_code_t err_code;

    log_init();

    // Initialize the async SVCI interface to bootloader before any interrupts are enabled.
    err_code = ble_dfu_buttonless_async_svci_init();
    APP_ERROR_CHECK(err_code);
    
    leds_init();
    timers_init();
    power_management_init();
    //buttons_leds_init(&erase_bonds);
    buttons_init();
    ble_stack_init();
    peer_manager_init();
    gap_params_init();
    gatt_init();
    services_init();
    advertising_init();
    conn_params_init();

    NRF_LOG_INFO("Buttonless DFU Application started.");

    // Start execution.
    application_timers_start();
    rtc_config();
    twi_init();
    nrf_drv_rtc_disable(&rtc);
    nrf_drv_rtc_tick_disable(&rtc);
    advertising_start(erase_bonds);
    
    // Enter main loop.
    for (;;)
    {
        idle_state_handle();
    }
}

Parents
  • Hello,

    The bootloader configures  button 4 pin as an input on startup, then it reads its input state to determine whether it should enter DFU mode or proceed to boot the main app. This mechanism can be removed by setting NRF_BL_DFU_ENTER_METHOD_BUTTON to '0' in the bootloader's sdk_config.h file. It will not affect the button configuration in your app however. So it does not explain why you end up in DFU mode.

    If you have not already tried, please debug the application to see if it ends up in the app error handler (see Error module). A runtime error could explain why the device is unexpectedly resetting into the bootloader.

  • Turns out the DFU mode was being entered because I was flashing the application incorrectly.  Merging the bootloader settings with my application before flashing with the softdevice and bootloader solved the problem.  However, I found that the cause of my issue with button 1 is an unknown error 12291 from my ble_lbs_on_button_change.  After some searching, I found that this could be BLE_ERROR_INVALID_ATTR_HANDLE, but I can't figure out where I went wrong defining my custom service.  The characteristic should be readable and writable by a connected device.

    /**@brief   Macro for defining a ble_cus instance.
     *
     * @param   _name   Name of the instance.
     * @hideinitializer
     */
    #define BLE_CUS_DEF(_name)                                                                          \
    static ble_cus_t _name;  
    
    /**@brief Custom Service init structure. This contains all options and data needed for
     *        initialization of the service.*/
    typedef struct
    {
        uint8_t                       initial_custom_value;           /**< Initial custom value */
        ble_srv_cccd_security_mode_t  custom_value_char_attr_md;     /**< Initial security level for Custom characteristics attribute */
    
    } ble_cus_init_t;
    
    /**@brief Custom Service structure. This contains various status information for the service. */
    struct ble_cus_s
    {
        uint16_t                      service_handle;                 /**< Handle of Custom Service (as provided by the BLE stack). */
        ble_gatts_char_handles_t      custom_value_handles;           /**< Handles related to the Custom Value characteristic. */
        ble_gatts_char_handles_t    button_char_handles;
        uint16_t                      conn_handle;                    /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
        uint8_t                       uuid_type; 
    };
    
    // Forward declaration of the ble_cus_t type.
    typedef struct ble_cus_s ble_cus_t;
    
    uint32_t ble_cus_init(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init);
    
    uint32_t ble_lbs_on_button_change(uint16_t conn_handle, ble_cus_t * p_lbs, uint8_t * button_state);
    /**@brief Function for adding the Custom Value characteristic.
     *
     * @param[in]   p_cus        Custom Service structure.
     * @param[in]   p_cus_init   Information needed to initialize the service.
     *
     * @return      NRF_SUCCESS on success, otherwise an error code.
     */
    
    static uint32_t custom_value_char_add(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
    {
        uint32_t            err_code;
        ble_gatts_char_md_t char_md;
        ble_gatts_attr_md_t cccd_md;
        ble_gatts_attr_t    attr_char_value;
        ble_uuid_t          ble_uuid;
        ble_gatts_attr_md_t attr_md;
    
        memset(&char_md, 0, sizeof(char_md));
    
        char_md.char_props.read   = 1;
        char_md.char_props.write  = 1;
        char_md.char_props.notify = 1; 
        char_md.p_char_user_desc  = NULL;
        char_md.p_char_pf         = NULL;
        char_md.p_user_desc_md    = NULL;
        char_md.p_cccd_md         = NULL; 
        char_md.p_sccd_md         = NULL;
    		
        memset(&attr_md, 0, sizeof(attr_md));
    
        attr_md.read_perm  = p_cus_init->custom_value_char_attr_md.read_perm;
        attr_md.write_perm = p_cus_init->custom_value_char_attr_md.write_perm;
        attr_md.vloc       = BLE_GATTS_VLOC_STACK;
        attr_md.rd_auth    = 0;
        attr_md.wr_auth    = 0;
        attr_md.vlen       = 0;
    
        ble_uuid.type = p_cus->uuid_type;
        ble_uuid.uuid = CUSTOM_VALUE_CHAR_UUID;
    
        memset(&attr_char_value, 0, sizeof(attr_char_value));
    
        attr_char_value.p_uuid    = &ble_uuid;
        attr_char_value.p_attr_md = &attr_md;
        attr_char_value.init_len  = 14;
        attr_char_value.init_offs = 0;
        attr_char_value.max_len   = 14;
    
    
        err_code = sd_ble_gatts_characteristic_add(p_cus->service_handle, &char_md,
                                                   &attr_char_value,
                                                   &p_cus->custom_value_handles);
        
        if (err_code != NRF_SUCCESS)
        {
            return err_code;
        }
    
        return NRF_SUCCESS;
    }
    
    /**@brief Function for initializing the Custom Service.
     *
     * @param[out]  p_cus       Custom Service structure. This structure will have to be supplied by
     *                          the application. It will be initialized by this function, and will later
     *                          be used to identify this particular service instance.
     * @param[in]   p_cus_init  Information needed to initialize the service.
     *
     * @return      NRF_SUCCESS on successful initialization of service, otherwise an error code.
     */
    
    uint32_t ble_cus_init(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
    {
        if (p_cus == NULL || p_cus_init == NULL)
        {
            return NRF_ERROR_NULL;
        }
    
        uint32_t   err_code;
        ble_uuid_t ble_uuid;
    
        //Initialize service structure
        p_cus->conn_handle               = BLE_CONN_HANDLE_INVALID;
    
        // Add Custom Service UUID
        ble_uuid128_t base_uuid = {CUSTOM_SERVICE_UUID_BASE};
        err_code =  sd_ble_uuid_vs_add(&base_uuid, &p_cus->uuid_type);
        VERIFY_SUCCESS(err_code);
        
        ble_uuid.type = p_cus->uuid_type;
        ble_uuid.uuid = CUSTOM_SERVICE_UUID;
    
        // Add the Custom Service
        err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_cus->service_handle);
        if (err_code != NRF_SUCCESS)
        {
            return err_code;
        }
    
        // Add Custom Value characteristic
        return custom_value_char_add(p_cus, p_cus_init);
    }
    
    
    
    uint32_t ble_lbs_on_button_change(uint16_t conn_handle, ble_cus_t * p_lbs, uint8_t * button_state)//button_state is the value sent
    {
        ble_gatts_hvx_params_t params;
        uint16_t len = 14;
    
            uint8_t arr[10];
    
            for(int i = 0; i < 10; i++){
                printf("Data Array[%d]: %d\n", i, *button_state);
                arr[i] = *button_state;
                button_state++;
            }
            
        memset(&params, 0, sizeof(params));
        params.type   = BLE_GATT_HVX_NOTIFICATION;
        params.handle = p_lbs->button_char_handles.value_handle;
        params.offset = 0;    
        params.p_data = arr;
        params.p_len  = &len;
    
        return sd_ble_gatts_hvx(conn_handle, &params);
    }

  • sd_ble_gatts_hvx() in ble_lbs_on_button_change() will return with BLE_ERROR_INVALID_ATTR_HANDLE if you pass an invalid attribute handle to it.

    Does it work if you change this line in ble_lbs_on_button_change():

        params.handle = p_lbs->button_char_handles.value_handle;

    with this:

        params.handle = p_lbs->custom_value_handles.value_handle;

    ?

    Your sd_ble_gatts_characteristic_add() call in custom_value_char_add()  populates the att handles in 'custom_value_handles', and  not in 'button_char_handles'.

Reply
  • sd_ble_gatts_hvx() in ble_lbs_on_button_change() will return with BLE_ERROR_INVALID_ATTR_HANDLE if you pass an invalid attribute handle to it.

    Does it work if you change this line in ble_lbs_on_button_change():

        params.handle = p_lbs->button_char_handles.value_handle;

    with this:

        params.handle = p_lbs->custom_value_handles.value_handle;

    ?

    Your sd_ble_gatts_characteristic_add() call in custom_value_char_add()  populates the att handles in 'custom_value_handles', and  not in 'button_char_handles'.

Children
  • I did not notice the button_char_handles in place of the custom_value_handles, but unfortunately, after making the modification the problem still persists

  • Are you able to debug the code and check if the  value handle assigned by  sd_ble_gatts_characteristic_add() has the same value when it's used in ble_lbs_on_button_change()?

    I can debug it here as well if you are able to share your project.

  • The value handles are the same between sd_ble_gatts_characteristic_add and ble_lbs_on_button_change but the handles are empty in both.  I spent some time today trying to figure out why, and where I could have deviated from the custom ble service tutorial on Github, but couldn't get any futher.  My project can be found here https://github.com/joeyp2k/Cuitt-NRF/tree/main/Desktop/Engineering/Cuitt/Development/nRF5_SDK_17.0.0_9d13099/examples/ble_peripheral/ble_app_buttonless_dfu  I am using the s132 and button 1 works the main function I am trying to run.

  • Thanks for sharing the project. The problem was that you were declaring the 'm_cus' variable in a header file causing m_cus to become redeclared in every source you inserted the header in.

    The pointer you passed to ble_lbs_on_button_change() was pointing to the zero initialized 'm_cus' varible declared in voltage.c, and not m_cus in main.c that was initilized by ble_cus_init().

    A simple fix is to declare it in main.c then remove the "ble_cus_t * p_lbs" paramater from your ble_lbs_on_button_change() function so you don't have to share the variable across source files:

    diff --git a/main.c b/main.c
    index 6dd3e65..27f6484 100644
    --- a/main.c
    +++ b/main.c
    @@ -91,6 +91,8 @@
    @@ -125,6 +127,8 @@ uint8_t sec, min, hr, day, date, month, year;
     NRF_BLE_GATT_DEF(m_gatt);                                                           /**< GATT module instance. */
     NRF_BLE_QWR_DEF(m_qwr);                                                             /**< Context for the Queued Write module.*/
     BLE_ADVERTISING_DEF(m_advertising);                                            /**< Advertising module instance. */
    +BLE_CUS_DEF(m_cus);    
    +
     
     static void advertising_start(bool erase_bonds);                                    /**< Forward declaration of advertising start function */
     
    --- a/pca10040/s132/ses/ble_cus.c
    +++ b/pca10040/s132/ses/ble_cus.c
    @@ -8,6 +8,9 @@
     #include "nrf_log.h"
     
     
    +static ble_cus_t * mp_cus;
    +
    +
     /**@brief Function for adding the Custom Value characteristic.
      *
      * @param[in]   p_cus        Custom Service structure.
    @@ -124,6 +127,8 @@ uint32_t ble_cus_init(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
         uint32_t   err_code;
         ble_uuid_t ble_uuid;
     
    +    mp_cus = p_cus;
    +
         //Initialize service structure
         p_cus->conn_handle               = BLE_CONN_HANDLE_INVALID;
     
    @@ -148,7 +153,7 @@ uint32_t ble_cus_init(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
     
     
     
    -uint32_t ble_lbs_on_button_change(uint16_t conn_handle, ble_cus_t * p_lbs, uint8_t * button_state)//button_state is the value sent
    +uint32_t ble_lbs_on_button_change(uint16_t conn_handle, uint8_t * button_state)//button_state is the value sent
     {
         ble_gatts_hvx_params_t params;
         uint16_t len = 14;
    @@ -163,7 +168,7 @@ uint32_t ble_lbs_on_button_change(uint16_t conn_handle, ble_cus_t * p_lbs, uint8
             
         memset(&params, 0, sizeof(params));
         params.type   = BLE_GATT_HVX_NOTIFICATION;
    -    params.handle = p_lbs->custom_value_handles.value_handle;
    +    params.handle = mp_cus->custom_value_handles.value_handle;
         params.offset = 0;    
         params.p_data = arr;
         params.p_len  = &len;
    diff --git a/pca10040/s132/ses/ble_cus.h b/pca10040/s132/ses/ble_cus.h
    index 50d14b6..9215545 100644
    --- a/pca10040/s132/ses/ble_cus.h
    +++ b/pca10040/s132/ses/ble_cus.h
    @@ -43,4 +43,4 @@ typedef struct ble_cus_s ble_cus_t;
     
     uint32_t ble_cus_init(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init);
     
    -uint32_t ble_lbs_on_button_change(uint16_t conn_handle, ble_cus_t * p_lbs, uint8_t * button_state);
    +uint32_t ble_lbs_on_button_change(uint16_t conn_handle, uint8_t * button_state);
    diff --git a/pca10040/s132/ses/voltage.c b/pca10040/s132/ses/voltage.c
    index 01b593c..1c357dc 100644
    --- a/pca10040/s132/ses/voltage.c
    +++ b/pca10040/s132/ses/voltage.c
    @@ -262,7 +262,7 @@ void transmit_packet(){
             while(stack_size > 0){
                 //send stack
                 printf("__________BLE transmit attempt___________\n");
    -            err_code = ble_lbs_on_button_change(m_conn_handle, &m_cus, arr);
    +            err_code = ble_lbs_on_button_change(m_conn_handle, arr);
                 if(err_code == NRF_SUCCESS){
                   printf("BLE transmit complete\n");
                   transmit_success = true;
    @@ -282,7 +282,7 @@ void transmit_packet(){
             }
             //send current draw
             printf("__________BLE transmit attempt___________\n");
    -        err_code = ble_lbs_on_button_change(m_conn_handle, &m_cus, arr);
    +        err_code = ble_lbs_on_button_change(m_conn_handle, arr);
             if(err_code == NRF_SUCCESS){
               printf("BLE transmit complete\n");
               transmit_success = true;
    diff --git a/pca10040/s132/ses/voltage.h b/pca10040/s132/ses/voltage.h
    index 76426a6..6a007c0 100644
    --- a/pca10040/s132/ses/voltage.h
    +++ b/pca10040/s132/ses/voltage.h
    @@ -13,7 +13,7 @@
     #define RED_LED                         BSP_BOARD_LED_1                         /**< Is on when device has connected. */
     #define GREEN_LED                       BSP_BOARD_LED_2   
     
    -BLE_CUS_DEF(m_cus);                          /**< Handle of the current connection. */
    +                      /**< Handle of the current connection. */
     
     extern uint16_t Draw_length;
     extern uint16_t Draw_length_average;
    

Related