Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

I am almost desperate: How to add battery service to UART sample correctly?

Dear Sir/Madam,

I tried to add battery service to the sample "ble_app_uart", but the code doesn't send notifications to cell phone. I struggled for several days and try compare the code with "ble_app_hrs", but still fail to find a solution. Could you tell me what I missed?  

Here is what I did to "ble_app_uart", and I also attached the code:

I worked on Keil MDK5.12, using SDK12.2,  S130,  and using the DK board (PCA10028).

1)Firstly I added the ble_bas.c to the project. I also added the path "components\ble\ble_services\ble_bas"to the project path ,so that the compiler could find the ble_bas.h file. 

2) I then defined an instance for battery service, and added the init code for battery service in services_ini() function:  Here is the services_init().

#include "ble_bas.h"

static ble_bas_t                        m_bas; 

static void services_init(void)
{
uint32_t err_code;
ble_nus_init_t nus_init;


memset(&nus_init, 0, sizeof(nus_init));
nus_init.data_handler = nus_data_handler;
err_code = ble_nus_init(&m_nus, &nus_init);
APP_ERROR_CHECK(err_code);

ble_bas_init_t bas_init;
memset(&bas_init, 0, sizeof(bas_init));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.cccd_write_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&bas_init.battery_level_char_attr_md.write_perm);

BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_report_read_perm);

bas_init.evt_handler = NULL;
bas_init.support_notification = true;
bas_init.p_report_ref = NULL;
bas_init.initial_batt_level = 100;

err_code = ble_bas_init(&m_bas,&bas_init);
APP_ERROR_CHECK(err_code);

}

3)Because I want care whether battery level changes or not. I commented the line of  "if (battery_level != p_bas->battery_level_last)"  in ble_bas_battery_level_update() function, so that I always get notification for each updates.

4)  I modified the main() so that the battery service could send out notifications by its battery level characteristic notification. The following is the main()

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

// Initialize.
APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false);
uart_init();

buttons_leds_init(&erase_bonds);
ble_stack_init();
gap_params_init();
services_init();
advertising_init();
conn_params_init();

printf("\r\nUART Start!\r\n");
err_code = ble_advertising_start(BLE_ADV_MODE_FAST);
APP_ERROR_CHECK(err_code);

// Enter main loop.
for (;;)
{
    power_manage();
    int t;    
    for(t=0; t< 100; t++){
        ble_bas_battery_level_update(&m_bas, t);

        APP_ERROR_CHECK(err_code);
        for(int i=0; i<1000; i++) ;   //for some delay
    }

  }

}

4) Then I compiled, and load it to DK board. 

The board then starts flashing. I then run Android App "BLE Reader", the App found the "Nordic_UART" device, and connected. It then listed the service it found. There was the battery service and battery level characteristic with "Read".  When I click on the battery level characteristic, the App display "Listening", but nothing came out.  If I click "Read" button, I could see the battery level reading is always "C", and the battery level seems never changed.

Could you help me fix this problem? I guess I have missed something, but I don't know where it is. I even checked the ble_app_hrs code, and still didn't get it.

Thanks,

Jacky

Parents
  • Hi Jacky

    Your init code seems fine, but you might be forgetting to forward BLE events to the BAS module.

    Basically you need to add the following line of code to the ble_evt_dispatch(..) function in main.c:

    ble_bas_on_ble_evt(&m_bas, p_ble_evt);

    With that in place I was able to update the battery service, and see the changes in the mobile app. 

    Also, I don't like the way you update the battery value in a loop after the power manage function. I would recommend using an app_timer callback instead, and update the battery value from there. 
    I attached the main file from my own test application, which does it this way. 

    Best regards
    Torbjørn

  • Hi Torbjorn,

    Thank you so much for the message !  Yes, it worked after added the line. 

    I just have another question. My main.c loop just blindly sending out battery level data. I wish I could know how to get the status of "Notification" so that I know when to start sending out battery level data, and when to stop ?  

    Thanks,

    Jacky

  • Hi Jacky

    You have to create an event handler for the battery service, similar to how the example already has an event handler for the UART service. 

    The BAS event handler should look something like this:

    void ble_bas_evt_handler(ble_bas_t * p_bas, ble_bas_evt_t * p_evt)
    {
      switch(p_evt->evt_type)
      {
        case BLE_BAS_EVT_NOTIFICATION_ENABLED:
          // Add your code here
          break;

        case BLE_BAS_EVT_NOTIFICATION_DISABLED:
          // Add your code here
          break;

        default:
          break;
      }
    }

    And then you have to set the event handler when you initialize the service (right now the event handler is just set to NULL): 

    bas_init.evt_handler = ble_bas_evt_handler;

    Best regards
    Torbjørn

Reply
  • Hi Jacky

    You have to create an event handler for the battery service, similar to how the example already has an event handler for the UART service. 

    The BAS event handler should look something like this:

    void ble_bas_evt_handler(ble_bas_t * p_bas, ble_bas_evt_t * p_evt)
    {
      switch(p_evt->evt_type)
      {
        case BLE_BAS_EVT_NOTIFICATION_ENABLED:
          // Add your code here
          break;

        case BLE_BAS_EVT_NOTIFICATION_DISABLED:
          // Add your code here
          break;

        default:
          break;
      }
    }

    And then you have to set the event handler when you initialize the service (right now the event handler is just set to NULL): 

    bas_init.evt_handler = ble_bas_evt_handler;

    Best regards
    Torbjørn

Children
No Data
Related