This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
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

How do I show the status of an LED with a ble advertising packet using nRF52840-dk?

Hi,

I am writing a program to actively change the state of an LED, then sample the output voltage on the led pin using SAADC, then outputs the adc value to terminal every two seconds, and also sends the status of the LED in a BLE advertising packet. I am unsure of how to dynamically broadcast the led status as a part of the ble advertising packet. Do I create a new service and display the LED info there? How is this done? nrf_sdk_15.3.0

Thanks,

A

Parents
  • Hi,

    Are you planning to do a connection or just advertising(broadcasting)? If the former then you should setup a custom service, if the latter then you should use the manufacturing data field to display the data. 

    regards

    Jared

  • I am just advertising. I am using the manuf specific data field to display the led status but I cannot get it to update dynamically. I am trying to use ble_advertising_advdata_update() but its not working.

    #include <stdbool.h>
    #include <stdint.h>
    #include <string.h>
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #include "app_timer.h"
    
    #include "bsp_btn_ble.h"
    
    #include "nrf_pwr_mgmt.h"
    
    #include "nrf_sdh.h"
    #include "nrf_sdh_ble.h"
    #include "nrf_sdh_soc.h"
    
    #include "nrf_ble_qwr.h"
    
    #include "nrf_ble_gatt.h"
    
    #include "ble_advdata.h"
    #include "ble_advertising.h"
    
    #include "ble_conn_params.h"
    
    #include "boards.h"
    
    #include "nrf_drv_saadc.h"
    #include "nrf_drv_gpiote.h"
    
    #define ADC_INTERVAL           APP_TIMER_TICKS(2000)
    #define SECOND_STATUS_INTERVAL APP_TIMER_TICKS(5000)
    
    APP_TIMER_DEF(m_app_timer_id);
    APP_TIMER_DEF(m_app_timer_id1);
    
    #define APP_BLE_CONN_CFG_TAG   1 
    #define APP_BLE_OBSERVER_PRIO  3  
    
    
    #define DEVICE_NAME            "Aaron's nRF BT"
    
    #define MIN_CONN_INTERVAL      MSEC_TO_UNITS(100, UNIT_1_25_MS)
    #define MAX_CONN_INTERVAL      MSEC_TO_UNITS(200, UNIT_1_25_MS)
    #define SLAVE_LATENCY          0
    #define CONN_SUP_TIMEOUT       MSEC_TO_UNITS(2000, UNIT_10_MS);
    
    #define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(5000)
    #define NEXT_CONN_PARAMS_UPDATE_DELAY  APP_TIMER_TICKS(30000)
    #define MAX_CONN_PARAMS_UPDATE_COUNT   3
    
    
    #define APP_ADV_INTERVAL       300
    #define APP_ADV_DURATION       0
    
    
    #define BUTTON 12
    
    #define SAMPLE_BUFFER_LEN 1
    
    enum state {none, first, second, third} status;
    
    static nrf_saadc_value_t m_buffer_pool[2][SAMPLE_BUFFER_LEN];
    
    NRF_BLE_QWR_DEF(m_qwr);
    NRF_BLE_GATT_DEF(m_gatt);
    BLE_ADVERTISING_DEF(m_advertising);
    
    static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;
    
    uint32_t count;
    
    float volts;
    
    
    //added to attempt dynamic data packets
    //define a timer handle for dynamic data
    APP_TIMER_DEF(m_adv_data_update_timer);
    
    //define a data update interval
    #define ADV_DATA_UPDATE_INTERVAL        APP_TIMER_TICKS(5000)
    
    #define MANUF_PAYLOAD_1 0x31 //led on
    #define MANUF_PAYLOAD_2 0x32 //led off
    
    #define PAYLOAD_SIZE                    1
    #define TOP_INDEX                       1
    
    #define APP_COMPANY_IDENTIFIER          0x0059                                  /**< Company identifier for Nordic Semiconductor ASA. as per www.bluetooth.org. */
      
    static ble_advdata_t                    new_advdata;
    
    
    static uint8_t manufacturing_data_payload_list[] = 
    {
        MANUF_PAYLOAD_1,
        MANUF_PAYLOAD_2
    };
    
    //timer handler for ADC sample
    static void app_timer_handler(void * p_context){
    
       nrfx_saadc_sample();
    
    }
    
    //timer handler for second status blinky
    static void app_timer_handler1(void * p_context){
    
       if(status == 2){
        
       bsp_board_led_invert(2);
    
       }
    
    }
    
    
    /*****************************************************************************************************
    *analog to digital event handler
    *****************************************************************************************************/
    void saadc_callback_handler(nrf_drv_saadc_evt_t const * p_event){
    
      float val;
    
      if(p_event->type == NRFX_SAADC_EVT_DONE){
      
        ret_code_t err_code;
    
        err_code = nrfx_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLE_BUFFER_LEN);
        APP_ERROR_CHECK(err_code);
    
        int i = 0;
    
          val = p_event->data.done.p_buffer[i] * 3.6 / 4096;
          volts = val;
    
          if(val < 1){
          
            NRF_LOG_INFO("The LED is ON with an ADC value of: ")
          }
          else{
          
            NRF_LOG_INFO("The LED is OFF with an ADC value of: ");
          }
    
          NRF_LOG_INFO("sample read: %d", p_event->data.done.p_buffer[i]);
    
          NRF_LOG_INFO("Voltage read: " NRF_LOG_FLOAT_MARKER "\r\n", NRF_LOG_FLOAT(val));
    
      }
    
    }
    
    
    /********************************************************************************************************
    *initialize the analog to digital converter
    ********************************************************************************************************/
    void saadc_init(void){
    
      ret_code_t err_code;
    
      nrf_saadc_channel_config_t channel_config = NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7);
    
      err_code = nrf_drv_saadc_init(NULL, saadc_callback_handler);
      APP_ERROR_CHECK(err_code);
    
      err_code = nrfx_saadc_channel_init(0,&channel_config);
      APP_ERROR_CHECK(err_code);
    
      err_code = nrfx_saadc_buffer_convert(m_buffer_pool[0], SAMPLE_BUFFER_LEN);
      APP_ERROR_CHECK(err_code);
    
      err_code = nrfx_saadc_buffer_convert(m_buffer_pool[1], SAMPLE_BUFFER_LEN);
      APP_ERROR_CHECK(err_code);
    }
    
    
    /********************************************************************************
    *event handler for button press to update status
    ********************************************************************************/
    void input_pin_handle(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action){
    
      if(status < 3){
    
        status++;
    
      }
    
      else{status = first;}
    
    }
    
    
    /************************************************************
    *create an interrupt when the button is pressed
    *************************************************************/
    void gpio_init(){
    
      ret_code_t err_code; //hold error value
    
      err_code = nrf_drv_gpiote_init();
      APP_ERROR_CHECK(err_code);
    
      nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true);//16MHz clk
      in_config.pull = NRF_GPIO_PIN_PULLUP;
    
      err_code = nrf_drv_gpiote_in_init(BUTTON,&in_config,input_pin_handle);
      APP_ERROR_CHECK(err_code);
    
      nrf_drv_gpiote_in_event_enable(BUTTON,true);
    }
    
    /********************************************************************************
    *event handler to update ble packet data
    * TODO: FIX, DOES NOT WORK
    ********************************************************************************/
    static void adv_data_update_timer_handler(void * p_context)
    {
        ret_code_t                  err_code;
        ble_advdata_manuf_data_t    manuf_data;
    
        new_advdata.p_manuf_specific_data = &manuf_data;
    
        static uint8_t payload_index = 0;
    
        // TODO change payload index depending on ADC status of pin
    
        //NRF_LOG_INFO("Voltage read: " NRF_LOG_FLOAT_MARKER "\r\n", NRF_LOG_FLOAT(volts));
    
        if(volts > 2){
        
          payload_index = 1;
         
        }
    
        NRF_LOG_INFO("Updating advertising data!");
        
        manuf_data.company_identifier = APP_COMPANY_IDENTIFIER;
    
        //manuf_data.data.p_data = manufacturing_data_payload_list + payload_index;
       // manuf_data.data.size = PAYLOAD_SIZE;
    
        manuf_data.data.p_data = "1";
        manuf_data.data.size = 1;
        
        err_code = ble_advertising_advdata_update(&m_advertising, &new_advdata, NULL);
        APP_ERROR_CHECK(err_code);  
        
        /*if(payload_index == TOP_INDEX)
        {
            payload_index = 0;
        }
        else
        {
            payload_index++;
        }*/
    
        NRF_LOG_INFO("Advertising data updated!");
    
    }
    
    
    //6th step: gap initialization
    static void gap_params_init(void){
    
      ret_code_t err_code;
    
      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);
    
      err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)DEVICE_NAME, strlen(DEVICE_NAME));
      APP_ERROR_CHECK(err_code);
    
      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;
    
      err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
      APP_ERROR_CHECK(err_code);
    
    
    }
    
    
    //7th step: gatt initialization
    static void gatt_init(void){
    
      ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, NULL);
      APP_ERROR_CHECK(err_code);
    }
    
    
    //step 9.1 error handler for queue writer
    static void nrf_qwr_error_handler(uint32_t nrf_error){
      
      APP_ERROR_HANDLER(nrf_error);
    }
    
    
    
    //9th step: Initialize the services
    static void services_init(){
    
      ret_code_t err_code;
    
      nrf_ble_qwr_init_t qwr_init = {0};
    
      qwr_init.error_handler = nrf_qwr_error_handler;
    
      err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
      APP_ERROR_CHECK(err_code);
     }
    
    
    //step 10.1 create an event handler for connection parameters update
    static void on_conn_params_evt(ble_conn_params_evt_t * p_evt){
    
      ret_code_t err_code;
    
      if(p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED){
        
        err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
        APP_ERROR_CHECK(err_code);
    
      }
      if(p_evt->evt_type == BLE_CONN_PARAMS_EVT_SUCCEEDED){
      
        
      }
    }
    
    
    //step 10.2 create an error handler for conn params update
    static void conn_params_error_handler(uint32_t nrf_error){
    
      APP_ERROR_HANDLER(nrf_error);
    }
    
    
    
    //10th step: create a function for setting up the connection parameters
    static void conn_params_init(void){
    
      ret_code_t err_code;
    
      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.disconnect_on_fail = false;
    
      cp_init.error_handler = conn_params_error_handler;
    
      cp_init.evt_handler = on_conn_params_evt;
    
      err_code = ble_conn_params_init(&cp_init);
      APP_ERROR_CHECK(err_code);
    
    
    }
    
    
    
    //step 8.1: create advertisement event handler
    static void on_adv_evt(ble_adv_evt_t ble_adv_evt){
    
      ret_code_t err_code;
    
      switch (ble_adv_evt){
      
        case BLE_ADV_EVT_FAST:
    
        NRF_LOG_INFO("Fast advertising.");
        err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
        APP_ERROR_CHECK(err_code);
        break;
    
        case BLE_ADV_EVT_IDLE:
        NRF_LOG_INFO("advertising idle.");
        err_code = bsp_indication_set(BSP_INDICATE_IDLE);
        APP_ERROR_CHECK(err_code);
    
        default:
        break;
      }
    }
    
    
    //8th step: advertising initialization
    static void advertising_init(void){
    
      ret_code_t err_code;
    
      ble_advertising_init_t init;
    
      memset(&init, 0, sizeof(init));
    
      //try manufac custom data in packet
      ble_advdata_manuf_data_t                  manuf_data; //Variable to hold manufacturer specific data
      uint8_t data[]                          = "2"; //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;
    
       //
    
     
    
      init.advdata.name_type = BLE_ADVDATA_FULL_NAME;
    
      init.advdata.include_appearance = true;
    
      init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
    
      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);
    
    
    }
    
    
    //step 5.1: BLE event handler
    static void ble_evt_handler(ble_evt_t const *p_ble_evt, void * p_context){
    
      ret_code_t err_code = NRF_SUCCESS;
    
      switch(p_ble_evt->header.evt_id){
      
        case BLE_GAP_EVT_DISCONNECTED:
    
        NRF_LOG_INFO("Device is disconnected.");
    
        break;
    
        case BLE_GAP_EVT_CONNECTED:
    
        NRF_LOG_INFO("Device is 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_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;
    
      }
    }
    
    
    //5th step: ble stack init
    static void ble_stack_init(){
    
      ret_code_t err_code;
      
      err_code = nrf_sdh_enable_request();
      APP_ERROR_CHECK(err_code);
    
      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);
    
      err_code = nrf_sdh_ble_enable(&ram_start);
      APP_ERROR_CHECK(err_code);
    
      NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
    }
    
    //4th step: create a function to initialize the power management
    static void power_management_init(void){
    
      ret_code_t err_code = nrf_pwr_mgmt_init();
      APP_ERROR_CHECK(err_code);
    }
    
    
    //3rd step: inialize bsp(leds)
    static void leds_init(void){
    
      ret_code_t err_code = bsp_init(BSP_INIT_LEDS, NULL);
      APP_ERROR_CHECK(err_code);
    }
    
    
    
    //2nd step: initialize app timer
    static void timers_init(void){
    
      ret_code_t err_code = app_timer_init();
      APP_ERROR_CHECK(err_code);
    
      err_code = app_timer_create(&m_adv_data_update_timer, 
                                      APP_TIMER_MODE_REPEATED, 
                                      adv_data_update_timer_handler);
    
      APP_ERROR_CHECK(err_code);
    
      //ADC SAMPLES
      err_code = app_timer_create(&m_app_timer_id, APP_TIMER_MODE_REPEATED, app_timer_handler);
      APP_ERROR_CHECK(err_code);
    
      //STAGE 2 BLINKY
      err_code = app_timer_create(&m_app_timer_id1, APP_TIMER_MODE_REPEATED, app_timer_handler1);
      APP_ERROR_CHECK(err_code);
    
    }
    
    
    /**@brief Function for starting timers.
     */
    static void application_timers_start(void)
    {
           ret_code_t err_code;
           err_code = app_timer_start(m_adv_data_update_timer, 
                                        ADV_DATA_UPDATE_INTERVAL, 
                                        NULL);
           APP_ERROR_CHECK(err_code);
    
           //ADC SAMPLES
           err_code = app_timer_start(m_app_timer_id, ADC_INTERVAL, NULL);
           APP_ERROR_CHECK(err_code);
    
           //STAGE 2 BLINKY
           err_code = app_timer_start(m_app_timer_id1, SECOND_STATUS_INTERVAL, NULL);
           APP_ERROR_CHECK(err_code);
    }
    
    
    //1st step: initialize the logger
    static void log_init(){
    
      ret_code_t err_code = NRF_LOG_INIT(NULL);
      APP_ERROR_CHECK(err_code);
    
      NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    //step 4.1: idle state handler
    static void idle_state_handle(void){
    
      if(NRF_LOG_PROCESS() == false){
        
        nrf_pwr_mgmt_run();
      }
    }
    
    //11th step: create a function which will start the advertisement
    static void advertising_start(void){
    
      ret_code_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
      APP_ERROR_CHECK(err_code);
    
    }
    
    
    
    int main(void)
    {
        log_init();
    
        timers_init();
    
        leds_init();
    
        saadc_init();
    
        gpio_init();
    
        power_management_init();
    
        ble_stack_init();
    
        gap_params_init();
    
        gatt_init();
    
        advertising_init();
    
        services_init();
    
        conn_params_init();
    
        NRF_LOG_INFO("BLE Base application started...");
    
        application_timers_start();
    
        advertising_start();
    
        bsp_board_init(BSP_INIT_BUTTONS);
        bsp_board_init(BSP_INIT_LEDS);
    
    
        // Enter main loop.
        while (true)
        {
          switch (status){
          
            case none:
     
              bsp_board_led_off(2);
             
              break;
            
            case 1: //if the button has been pressed once, turn led on
             
              bsp_board_led_on(2);
    
              break;
    
            case second://if the button has been pressed twice, toggle led every 5s
              
              //handled by app timer interrupt
    
              break;
    
            case third:
    
              bsp_board_led_off(2);
    
              break;
          }
    
          idle_state_handle();
        }
    }

  • Does the program enter the app timer handler? Could you verify it by setting a breakpoint in the handler and see if the program enters it on a timeout. 

Reply Children
Related