LE Broadcaster

The LE broadcaster sample demonstrates how to use the LE GAP Broadcaster role to develop many different broadcaster-role based applications. LE GAP Broadcaster role can send non-connectable advertising events and it cannot create connections.

../../../_images/broadcaster_architecture.png

The sample uses LE host and LE manager module. The above figure shows the relationships between several modules in the sample.

More information about these modules can be found in the LE Host and LE Manager documentation.

Requirements

The sample supports the following development kits:

Hardware Platforms

Board Name

Build Target

RTL87x3E HDK

RTL87x3E EVB

ble_broadcaster_4M_bank0

ble_broadcaster_16M_bank0

RTL87x3D HDK

RTL87x3D EVB

ble_broadcaster_8M_bank0

ble_broadcaster_16M_bank0

ble_broadcaster_cs_16M_bank0

This sample project can be found under board\evb\ble_broadcaster in SDK folder structure. Developers can choose the project according to the Board Name and choose the Build Target according to the flash map.

When built for an xxx_4M_xxx build target, the sample is configured to build and run with a 4M flash map.

When built for an xxx_8M_xxx build target, the sample is configured to build and run with an 8M flash map.

When built for an xxx_16M_xxx build target, the sample is configured to build and run with a 16M flash map.

For more requirements, please refer to Quick Start.

Configurations

Configurable Items

All contents that can be configured for the sample are in src\sample\ble_broadcaster\app_broadcaster_flags.h, developers can configure according to actual needs.

/** @brief  Config DLPS: 0-Disable DLPS, 1-Enable DLPS */
#define F_BT_DLPS_EN                        1

/** @} */ /* End of group BROADCASTER_Config */

Building and Downloading

Take the project rtl87x3e_ble_broadcaster.uvprojx and target ble_broadcaster_4M_bank0 as an example, to build and run the sample with Keil development environment, follow the steps listed below:

  1. Open rtl87x3e_ble_broadcaster.uvprojx.

  2. Choose the build target ble_broadcaster_4M_bank0.

    ../../../_images/chose_build_target7.png
  3. Build the target.

    ../../../_images/building7.png

    After a successful build, the APP bin file ble_broadcaster_bank0_MP-v0.0.0.0-xxx.bin will be generated in the directory bin\rtl87x3e\flash_4M_dualbank\bank0.

  4. Download APP bin into EVB.

  5. Press reset button in EVB and it will start LE advertising.

Experimental Verification

After downloading the sample bin to the EVB, developers can test it either by using another kit that is running the LE Observer sample, or by using a phone which already has installed LE APPs like LightBlue.

Testing with Another Kit

For more information, please refer to the chapter Testing with Another Kit of LE Observer.

Testing with Phone

Prepare one development boards named DUT, and use Debug Analyzer tool to get the logs. For more information, please refer to Debug Analyzer.

Preparation Phase

  1. Use MCUConfig Tool to set DUT address to [00:11:22:33:44:80], and then build the LE broadcaster sample, and download images into DUT.

Testing Phase

  1. Press the reset button on DUT and DUT will start sending non-connectable undirected advertising events.

    If the advertisement is successfully enabled, the following Debug Analyzer log will be printed. If developers do not see the following log, it means that the advertisement failed to start. Please check if the software and hardware environment is configured correctly.

    [APP] app_broadcaster_adv_callback:BLE_EXT_ADV_MGR_ADV_ENABLED
    
  2. Run LightBlue on an iOS device to search for DUT.

    If the phone receives advertising data and scan response data, a screenshot shown as below:

    ../../../_images/Broadcaster_phone.jpg

    Developers can only implement scanning action on the phone-end because the advertising events sent by DUT is non-connectable.

Code Overview

The main purpose of this chapter is to help APP developers familiarize themselves with the development process related to Broadcaster Role. This chapter will be introduced according to the following several parts:

Source Code Directory

  • Project directory: samples\bluetooth\ble_broadcaster\proj.

  • Source code directory: samples\bluetooth\ble_broadcaster\src.

Source files in LE broadcaster sample project are currently categorized into several groups as below:

└── ble_observer_4M_bank0
    ├── include                  ROM UUID header files. Developers do not need to modify it.
    ├── lib                      Includes all binary symbol files that user application is built on.
        ├── gap_utils.lib
        ├── ROM.lib
        ├── upperstack_4M.lib
        ├── hal_utils.lib
        ├── ble_mgr.lib
        └── sysm.lib
    ├── cmsis                    The cmsis source code. Developers do not need to modify it.
    ├── app                      The application source code.
        ├── app_broadcaster_adv.c          Advertising manager
        ├── app_broadcaster_gap.c          LE GAP initialize and message handler
        ├── app_broadcaster_main.c         Main entry
        └── app_broadcaster_task.c         APP task
    └── io_hal

Initialization

main() function is invoked when the EVB is powered on and the chip is reset, and it performs the following initialization functions:

int main(void)
{
   board_init();
   le_gap_init(0);
   gap_lib_init();
   app_broadcaster_gap_init();
   pwr_mgr_init();
   task_init();
   os_sched_start();

   return 0;
}
  • le_gap_init() function is used to initialize GAP and configure link number.

  • app_broadcaster_gap_init() function is used to initialize the GAP parameters.

GAP Parameter Initialization

The app_broadcaster_gap_init() function is used to initialize the GAP parameters. Developers can easily customize the sample by modifying the following parameter values:

void app_broadcaster_gap_init(void)
{
     /* register GAP message callback */
     le_register_app_cb(app_broadcaster_gap_callback);

     /* LE manager module initialize*/
     app_broadcaster_gap_ble_mgr_init();

     /*advertising parameters initialize*/
     app_broadcaster_adv_init_nonconn_public();
}
  1. le_register_app_cb()

    Register GAP message callback function app_broadcaster_gap_callback() and all GAP callback messages will be handled in this callback.

  2. app_broadcaster_gap_ble_mgr_init()

    Initialize LE manager library module to config support LE advertisement and advertising set number. More information can be found in the chapter LE Manager Initialization of LE Manager.

    void app_broadcaster_gap_ble_mgr_init(void)
    {
       BLE_MGR_PARAMS param = {0};
       param.ble_ext_adv.enable = true;
       param.ble_ext_adv.adv_num = 1;
       ble_mgr_init(&param);
    }
    
  3. app_broadcaster_adv_init_nonconn_public()

    Initialize non-connectable advertising parameters and register advertising callback. More information can be found in the chapter LE Extended Advertising Manager of LE Manager.

    void app_broadcaster_adv_init_nonconn_public(void)
    {
       T_LE_EXT_ADV_LEGACY_ADV_PROPERTY adv_event_prop = LE_EXT_ADV_LEGACY_ADV_SCAN_UNDIRECTED;
       uint16_t adv_interval_min = 0xA0;
       uint16_t adv_interval_max = 0xB0;
       T_GAP_LOCAL_ADDR_TYPE own_address_type = GAP_LOCAL_ADDR_LE_PUBLIC;
       T_GAP_REMOTE_ADDR_TYPE peer_address_type = GAP_REMOTE_ADDR_LE_PUBLIC;
       uint8_t  peer_address[6] = {0, 0, 0, 0, 0, 0};
       T_GAP_ADV_FILTER_POLICY filter_policy = GAP_ADV_FILTER_ANY;
    
       ble_ext_adv_mgr_init_adv_params(&adv_handle, adv_event_prop, adv_interval_min,
                                       adv_interval_max, own_address_type, peer_address_type, peer_address,
                                       filter_policy, sizeof(adv_data), adv_data,
                                       sizeof(scan_rsp_data), scan_rsp_data, NULL);
    
       ble_ext_adv_mgr_register_callback(app_broadcaster_adv_callback, adv_handle);
    }
    

    A device in the broadcast mode shall send data using non-connectable advertising events. Therefore the parameter adv_evt_type should be configured as one of the following types:

    LE_EXT_ADV_LEGACY_ADV_SCAN_UNDIRECTED

    LE_EXT_ADV_LEGACY_ADV_NON_SCAN_NON_CONN_UNDIRECTED

More information on LE GAP initialization and startup flow can be found in the chapter GAP Parameters Initialization of LE Host.

GAP Message Handler

app_broadcaster_gap_handle_gap_msg() function is invoked whenever a GAP message is received from the Bluetooth Host. More information on GAP messages can be found in the chapter Bluetooth LE GAP Message of LE Host.

When the sample handles GAP message, the ble_mgr_handle_gap_msg() shall be called to handle the GAP message.

void app_broadcaster_gap_handle_gap_msg(T_IO_MSG *p_gap_msg)
{
   T_LE_GAP_MSG gap_msg;
   memcpy(&gap_msg, &p_gap_msg->u.param, sizeof(p_gap_msg->u.param));

   ble_mgr_handle_gap_msg(p_gap_msg->subtype, &gap_msg);
   APP_PRINT_TRACE1("app_broadcaster_gap_handle_gap_msg: subtype %d", p_gap_msg->subtype);

   switch (p_gap_msg->subtype)
   {
   case GAP_MSG_LE_DEV_STATE_CHANGE:
      {
         app_broadcaster_gap_handle_dev_state_evt(gap_msg.msg_data.gap_dev_state_change.new_state,
                                                   gap_msg.msg_data.gap_dev_state_change.cause);
      }
      break;

   default:
      APP_PRINT_ERROR1("app_broadcaster_gap_handle_gap_msg: unknown subtype %d",
                       p_gap_msg->subtype);
      break;
   }
}

The broadcaster sample will call app_broadcaster_adv_start() to start advertising when receiving GAP_INIT_STATE_STACK_READY. If app_broadcaster_adv_start() returns true, it means the Bluetooth Host has already received this command and is ready to execute. When this command execution completes, the Bluetooth Host will send BLE_EXT_ADV_MGR_ADV_ENABLED to app_broadcaster_adv_callback().

When the LE broadcaster sample runs on the EVB, the device will send non-connectable advertising events.

void app_broadcaster_gap_handle_dev_state_evt(T_GAP_DEV_STATE new_state, uint16_t cause)
{
    APP_PRINT_INFO3("app_broadcaster_gap_handle_dev_state_evt: init state %d, adv state %d, cause 0x%x",
                    new_state.gap_init_state, new_state.gap_adv_state, cause);
    if (gap_dev_state.gap_init_state != new_state.gap_init_state)
    {
        if (new_state.gap_init_state == GAP_INIT_STATE_STACK_READY)
        {
            APP_PRINT_INFO0("app_broadcaster_gap_handle_dev_state_evt: GAP stack ready");
            /*stack ready*/
            app_broadcaster_adv_start(0);
        }
    }

    gap_dev_state = new_state;
}

static void app_broadcaster_adv_callback(uint8_t cb_type, void *p_cb_data)
{
    T_BLE_EXT_ADV_CB_DATA cb_data;
    memcpy(&cb_data, p_cb_data, sizeof(T_BLE_EXT_ADV_CB_DATA));

    switch (cb_type)
    {
    case BLE_EXT_ADV_STATE_CHANGE:
        {
            APP_PRINT_TRACE2("app_broadcaster_adv_callback: adv_state %d, adv_handle %d",
                             cb_data.p_ble_state_change->state, cb_data.p_ble_state_change->adv_handle);
            adv_state = cb_data.p_ble_state_change->state;

            if (adv_state == BLE_EXT_ADV_MGR_ADV_ENABLED)
            {
                APP_PRINT_TRACE0("app_broadcaster_adv_callback: BLE_EXT_ADV_MGR_ADV_ENABLED");
            }
            else if (adv_state == BLE_EXT_ADV_MGR_ADV_DISABLED)
            {
                APP_PRINT_TRACE0("app_broadcaster_adv_callback: BLE_EXT_ADV_MGR_ADV_DISABLED");
                switch (cb_data.p_ble_state_change->stop_cause)
                {
                case BLE_EXT_ADV_STOP_CAUSE_APP:
                    break;

                case BLE_EXT_ADV_STOP_CAUSE_CONN:
                    break;

                case BLE_EXT_ADV_STOP_CAUSE_TIMEOUT:
                    break;

                default:
                    break;
                }
                APP_PRINT_TRACE2("app_broadcaster_adv_callback: stack stop adv cause 0x%x, app stop adv cause 0x%02x",
                                 cb_data.p_ble_state_change->stop_cause, cb_data.p_ble_state_change->app_cause);
            }
        }
        break;

    default:
        break;
    }
}

Troubleshooting

How to Modify the Parameters of Advertising Data?

The advertising data is defined in the following array adv_data, and developer can directly modify the content of the array to modify the advertising data.

static uint8_t adv_data[] =
{
   /* Flags */
   0x02,             /* length */
   GAP_ADTYPE_FLAGS, /* type="Flags" */
   GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,

   /* Local name */
   0x10,
   GAP_ADTYPE_LOCAL_NAME_COMPLETE,
   'B', 'L', 'E', '_', 'B', 'R', 'O', 'A', 'D', 'C', 'A', 'S', 'T', 'E', 'R'
};