LE Observer

ble_observer 示例工程可以作为开发基于 Observer 角色的 APP 的框架。

Observer 角色特征:

  • 可以收到可扫描广播事件。

  • 不能创建连线。

环境需求

该示例支持以下开发套件:

开发套件

Hardware Platforms

Board Name

RTL8752H HDK

RTL8752H EVB

为快速搭建起开发环境,可参考 快速入门 中提供的详细指导。

硬件连线

请参考 快速入门 中的 RTL8752H EVB 接口和模块

配置

配置选项

该示例工程全部配置选项在 src\sample\ble_observer\app_flags.h 中, 开发者可以根据实际需求配置。

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

/** @} */ /* End of group OB_Config */

编译和下载

该示例可以在 SDK 文件夹中找到:

Project file: board\evb\ble_observer\mdk

Project file: board\evb\ble_observer\gcc

编译和运行该示例请遵循以下步骤:

  1. 打开项目文件。

  2. 要编译目标文件,请参考 快速入门编译 APP Image 中列出的步骤。

  3. 编译成功后,目录 board\evb\ble_observer\mdk\bin 下会生成 app bin 文件 app_MP_sdk_xxx.bin

  4. 要下载 app bin 到 EVB,请参考 快速入门MP Tool 中列出的步骤。

  5. 在 EVB 上按下 reset 键,程序将开始运行。

测试验证

将示例工程烧录到 EVB 后,开发者可以使用另一个运行 LE Broadcaster 工程的开发板来进行测试。

与另一块开发板对测

准备两块开发板分别命名为 DUTTester 。 开发者可以使用 Debug AnalyzerLog 验证

准备步骤

  1. 使用 MP Tool 将 DUT 地址设为 [00:11:22:33:44:85],然后编译 ble_observer 示例工程,并将 images 下载至 DUT

  2. 使用 MP Tool 将 Tester 地址设为 [00:11:22:33:44:80],然后编译 ble_broadcaster 示例工程,并将 images 下载至 Tester。更多信息请参考 LE Broadcaster 文档中的 编译和下载

更多关于如何修改 蓝牙地址 的细节请查阅 快速入门 中的 生成 System Config File

测试步骤

  1. Tester 上的 reset 键, Tester 将开始发送不可连接的非定向广播。

    1. 如果成功启动广播,会打印下面的 Debug Analyzer 日志。

    2. 如果没有看到下列日志,说明广播启动失败,请检查软件和硬件环境。

    [APP] !**GAP adv start
    
  2. DUT 上的 reset 键, DUT 将开始扫描广播。

    1. DUT 的日志中,使用 Tester 的地址查找广播是否被扫描到。

    2. 如果 DUT 接收到广播数据和扫描响应数据,应用程序会接收到 GAP_MSG_LE_SCAN_INFO

    下面是日志:

    [APP]  GAP_MSG_LE_SCAN_INFO: bd_addr 00::11::22::33::44::80, bdtype 0, event 0x3, rssi -58, len 20
    

代码介绍

本章的主要目的是帮助开发者熟悉 Observer Role 相关的开发流程。本章将按照以下几个部分进行介绍:

源码路径

  • 工程目录: board\evb\ble_observer

  • 源码目录: src\sample\ble_observer

ble_observer 示例工程中的源文件当前被分为几个组,如下所示。

└── Project: observer
    └── ble_observer
        └── include
        ├── lib                      Includes all binary symbol files that user application is built on.
            ├── ROM.lib
            ├── gap_utils.lib
            ├── lowerstack.lib
            └── rtl8752h_sdk.lib
        ├── cmsis                    Includes startup code.
        ├── peripheral               Includes all peripheral drivers and module code used by the application.
        └── app                      Includes the ble_observer user application implementation.
            ├── app_task.c
            ├── main.c
            ├── observer_app.c
            └── overlay_mgr.c

示例工程使用与 upperstack_0_0 匹配的默认 GAP LIB,请参阅文档 Host Image 中的 GAP LIB 的使用方法 以获取更多信息。

Bluetooth Host 介绍

示例工程默认使用 Bluetooth Host image 版本 upperstack_0_0,更多信息可参阅 Host Image

关于 Bluetooth Host 所支持的蓝牙功能的详细信息,请参阅文件 bin\upperstack_img\upperstack_0_0\upperstack_config.h

初始化

当 EVB 启动并且芯片复位时, main() 函数将被调用,它执行以下初始化函数:

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

  return 0;
}
void app_le_gap_init(void)
{
    /* Scan parameters */
    uint8_t  scan_mode = GAP_SCAN_MODE_PASSIVE;
    uint16_t scan_interval = DEFAULT_SCAN_INTERVAL;
    uint16_t scan_window = DEFAULT_SCAN_WINDOW;
    uint8_t  scan_filter_policy = GAP_SCAN_FILTER_ANY;
    uint8_t  scan_filter_duplicate = GAP_SCAN_FILTER_DUPLICATE_ENABLE;

    /* Set Scan parameters */
    le_scan_set_param(GAP_PARAM_SCAN_MODE, sizeof(scan_mode), &scan_mode);
    le_scan_set_param(GAP_PARAM_SCAN_INTERVAL, sizeof(scan_interval), &scan_interval);
    le_scan_set_param(GAP_PARAM_SCAN_WINDOW, sizeof(scan_window), &scan_window);
    le_scan_set_param(GAP_PARAM_SCAN_FILTER_POLICY, sizeof(scan_filter_policy),
                      &scan_filter_policy);
    le_scan_set_param(GAP_PARAM_SCAN_FILTER_DUPLICATES, sizeof(scan_filter_duplicate),
                      &scan_filter_duplicate);

    /* register gap message callback */
    le_register_app_cb(app_gap_callback);
}

Observe 模式下的设备不需要发送 scan request PDUs,就会收到可扫描广播事件。因此 scan_mode 参数应被配置为 GAP_SCAN_MODE_PASSIVE 类型。

le_register_app_cb() 注册 GAP 消息的 callback 函数 app_gap_callback(),所有的 GAP callback 消息都将在这个函数中被处理。

更多关于 LE GAP 初始化和启动流程的信息可以查阅 LE Host 中的 GAP 参数的初始化

GAP 消息处理

当 APP 从 Bluetooth Host 接收到 GAP 消息时,函数 app_handle_gap_msg() 会被调用。 更多关于 GAP 消息的信息可以查阅 LE Host 中的 蓝牙状态消息

void app_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));

    APP_PRINT_TRACE1("app_handle_gap_msg: subtype %d", p_gap_msg->subtype);
    switch (p_gap_msg->subtype)
    {
    case GAP_MSG_LE_DEV_STATE_CHANGE:
        {
            app_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_handle_gap_msg: unknown subtype %d", p_gap_msg->subtype);
        break;
    }
}

ble_observer 示例工程会在收到 GAP_INIT_STATE_STACK_READY 时调用 le_scan_start() 来扫描广播。 如果 le_scan_start() 返回 true,说明 Bluetooth Host 已经接收了这个命令并准备执行,当这个命令执行完成后, Bluetooth Host 将发送 GAP_SCAN_STATE_SCANNINGapp_handle_dev_state_evt()。 当 ble_observer 示例工程在开发板上运行时,设备将收到可扫描广播事件,Bluetooth Host 会发送 GAP_MSG_LE_SCAN_INFOapp_gap_callback()ble_observer 示例工程会调用 app_parse_scan_info() 来处理广播数据和扫描响应数据。

void app_handle_dev_state_evt(T_GAP_DEV_STATE new_state, uint16_t cause)
{
    APP_PRINT_INFO3("app_handle_dev_state_evt: init state %d, scan state %d, cause 0x%x",
                    new_state.gap_init_state,
                    new_state.gap_scan_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("GAP stack ready");
            /*stack ready*/
            le_scan_start();
        }
    }

    if (gap_dev_state.gap_scan_state != new_state.gap_scan_state)
    {
        if (new_state.gap_scan_state == GAP_SCAN_STATE_IDLE)
        {
            APP_PRINT_INFO0("GAP scan stop");
        }
        else if (new_state.gap_scan_state == GAP_SCAN_STATE_SCANNING)
        {
            APP_PRINT_INFO0("GAP scan start");
        }
    }
    gap_dev_state = new_state;
}

GAP 回调函数处理

app_gap_callback() 函数用于处理 GAP 回调函数消息。 更多关于 GAP 回调函数的信息请参考 LE Host 中的 Bluetooth LE GAP 回调函数

当设备处于 scanning 模式时,它会收到广播数据。当收到广播数据或扫描响应数据时,GAP 层会发送 GAP_MSG_LE_SCAN_INFO 给应用。

T_APP_RESULT app_gap_callback(uint8_t cb_type, void *p_cb_data)
{
   T_APP_RESULT result = APP_RESULT_SUCCESS;
   T_LE_CB_DATA *p_data = (T_LE_CB_DATA *)p_cb_data;

   switch (cb_type)
   {
   case GAP_MSG_LE_SCAN_INFO:
       APP_PRINT_TRACE5("GAP_MSG_LE_SCAN_INFO: bd_addr %s, bdtype %d, event 0x%x, rssi %d, len %d",
                       TRACE_BDADDR(p_data->p_le_scan_info->bd_addr),
                       p_data->p_le_scan_info->remote_addr_type,
                       p_data->p_le_scan_info->adv_type,
                       p_data->p_le_scan_info->rssi,
                       p_data->p_le_scan_info->data_len);
       /* User can split interested information by using the function as follow. */
       app_parse_scan_info(p_data->p_le_scan_info);
       break;

   default:
       break;
   }
   return result;
}

备注

app_parse_scan_info() 是一个用于处理广播数据和扫描响应数据的示例函数。