LE Observer

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

observer角色特征:

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

  • 不能创建连线。

环境需求

该示例支持以下开发工具包:

环境需求

Hardware Platforms

Board Name

RTL87x2G HDK

RTL87x2G EVB

该示例还需要一个设备运行一个LE broadcaster角色,用于发送可扫描广播。 例如运行Broadcaster示例工程的另一块开发板。

更多要求,请参考 快速入门

硬件连线

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

配置选项

APP配置选项

APP所有需要配置的内容在 samples\bluetooth\ble_observer\src\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: samples\bluetooth\ble_observer\proj\rtl87x2g\mdk

Project file: samples\bluetooth\ble_observer\proj\rtl87x2g\gcc

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

  1. 打开项目文件。

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

  3. 编译成功后,目录 samples\bluetooth\ble_observer\proj\rtl87x2g\mdk\bin 下会生成app bin文件 app_MP_sdk_xxx.bin

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

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

测试验证

将示例工程烧录到EVB后,开发者可以使用另一个运行 LE Broadcaster 工程的开发板或者装有 LightBlue 之类LE应用的手机来进行测试。

与另一块开发板对测

准备两块开发板分别命名为 DUTTester 。 开发者可以使用 DebugAnalyzer 抓取Soc端Log

准备步骤

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

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

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

测试步骤

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

如果成功启动广播,会打印下面的 DebugAnalyser 日志。 如果没有看到下列日志,说明广播启动失败。请检查软件和硬件环境

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

DUT 的日志中,使用 Tester 的地址查找广播是否被扫描到。如果 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

代码介绍

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

源码路径

  • 工程目录: samples\bluetooth\ble_observer\proj

  • 源码目录: samples\bluetooth\ble_observer\src

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

└── Project: observer
    └── secure_only_app
        └── Device                   includes startup code
        ├── CMSE Library             Non-secure callable lib
        ├── Lib                      includes all binary symbol files that user application is built on
            ├── ROM_NS.lib
            └── lowerstack.lib
            └── rtl87x2g_sdk.lib
            └── gap_utils.lib
        ├── Peripheral               includes all peripheral drivers and module code used by the application
        ├── Profile                  includes LE profiles or services used by the sample application
        └── APP                      includes the ble_observer user application implementation
            ├── app_task.c
            ├── main.c
            └── observer_app.c

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

BT Host介绍

示例工程使用 bt_host_0_0 中的默认BT Host image,更多信息可参阅 BT Host Image

关于BT Host所支持的蓝牙功能的详细信息,请参阅文件 bin\rtl87x2g\bt_host_image\bt_host_0_0\bt_host_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从GAP层接收到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;
    }
}

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。 当Observer示例工程在开发板上运行时,设备将受到可扫描广播事件,Bluetooth Host会发送 GAP_MSG_LE_SCAN_INFOapp_gap_callback。 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() 是一个用于处理广播数据和扫描相应数据的示例函数。