IoT

BLE Scanner应用开发实例

1. 简介

BLE Scanner是一个常见的BLE Central应用。本文介绍了如何使用YoC蓝牙协议栈和CH6121开发板进行BLE Scanner应用开发的过程。

2. 应用开发

BLE Scanner应用主要实现了蓝牙设备的发现、连接、BLE Profile的发现以及操作。示例程序中通过扫描HRS设备,并与之建立连接通信,展示了BLE Central应用的主要工作流程。BLE Scanner应用的主要工作流程分为:

  • 应用初始化
  • 蓝牙协议栈事件处理
  • HRS服务及特征发现
  • 特征操作

2.1. 应用初始化

应用入口函数app_main(),主要实现如下功能:

  • 蓝牙协议栈的初始化,配置MAC地址及类型
  • 注册蓝牙协议栈事件回调处理函数
  • 开启扫描
  • HRS服务及特征发现

代码分析:

int app_main(int argc, char *argv[])
{
    /* 定义设备MAC地址以及地址类型 */
    dev_addr_t addr = {DEV_ADDR_LE_RANDOM, DEVICE_ADDR}; 
    /* 蓝牙协议栈初始化参数设置 */
    init_param_t init = {
        .dev_name = DEVICE_NAME,
        .dev_addr = &addr,
        .conn_num_max = 1,
    };   
    
    /* 板级初始化,各业务模块初始化 */
    board_yoc_init(); 
    ......

    /* 蓝牙协议栈初始化 */
    ble_stack_init(&init); 
    
    /* 注册蓝牙协议栈事件回调函数 */
    ble_stack_event_register(&ble_cb); 

    /* 开始扫描 */
    scan_work(NULL); 

    while (1) {
        aos_sem_wait(&sync_sem, 2000);

        if (g_mtu_exchanged) {
            /* MTU协商成功后,开始HRS服务发现*/
            ble_stack_gatt_discovery_primary(g_conn_handle, UUID_HRS, 0x0001, 0xFFFF);
            g_mtu_exchanged = 0;
        }

        /* 连接失败则2秒后重新开始扫描 */
        if (g_conn_handle == -1) {
            scan_work(NULL);
        }
    }

    return 0;
} 

2.2. 蓝牙协议栈事件处理

蓝牙协议栈的事件是通过event_callback()回调函数上报,应用程序需要对这些事件进行相应的处理:

  • 蓝牙设备发现事件
  • 连接成功或失败事件
  • MTU协商请求事件
  • 服务及特征发现事件
  • GATT Read、Write回调事件
  • GATT Notify事件

代码分析:

static int event_callback(ble_event_en event, void *event_data)
{    
switch (event) {
        /* 设备发现事件,用户可决定是否发起连接请求 */
        case EVENT_GAP_DEV_FIND:
            device_find(event, event_data);
            break;
        /* 连接成功或失败事件 */
        case EVENT_GAP_CONN_CHANGE:
            conn_change(event, event_data);
            break;
        /* MTU协商事件 */
        case EVENT_GATT_MTU_EXCHANGE:
            mtu_exchange(event, event_data);
            break;
        /* 服务发现事件 */
        case EVENT_GATT_DISCOVERY_SVC:
        case EVENT_GATT_DISCOVERY_CHAR:
        case EVENT_GATT_DISCOVERY_CHAR_DES:
        case EVENT_GATT_DISCOVERY_COMPLETE:
            service_discovery(event, event_data);
            break;
        /* 属性写操作事件 */
        case EVENT_GATT_CHAR_WRITE_CB: {
            evt_data_gatt_write_cb_t *e = event_data;
            LOGI(TAG, "GATT write %s", e->err ? "FAIL" : "SUCCESS");
            break;
        }
        /* 属性读操作事件 */
        case EVENT_GATT_CHAR_READ_CB: {
            evt_data_gatt_read_cb_t *e = event_data;
            char val_str[10] = {0};
            hex_to_str((uint8_t *)val_str, (uint8_t *)e->data, e->len);
            LOGI(TAG, "GATT read %s", val_str);
            break;
        }
        /* GATT通知事件 */
        case EVENT_GATT_NOTIFY: {
            evt_data_gatt_notify_t *e = event_data;
            char val_str[10] = {0};
            hex_to_str((uint8_t *)val_str, (uint8_t *)e->data, e->len);
            LOGI(TAG, "GATT notify %s", val_str);
            break;
        }        
        default:
            LOGW(TAG, "Unhandle event %x\n", event);
            break;
    }

    return 0;
}

2.2.1. 设备发现事件

发现蓝牙设备后,发起连接请求前,需要先停止广播,处理流程如下图:

image.png

2.2.2. 服务发现事件

HRS服务发现处理流程如下图:

image.png

  • 发现HRS服务的Primary Service,蓝牙协议栈将返回查询结果。成功发现Primary Service后,需要记录HRS服务的开始和结束句柄。
  • 发现HRS服务的所有特征,蓝牙协议栈将遍历所有的特征,并一一返回查询结果。全部特征查询完毕后,将返回EVENT_GATT_DISCOVERY_COMPLETE事件。
  • 发现HRS服务的所有特征描述符,蓝牙协议栈将遍历所有的特征描述符,并一一返回查询结果。全部特征描述符查询完毕后,也是返回EVENT_GATT_DISCOVERY_COMPLETE事件。
  • 开始进行GATT Read、Write操作。

2.2.3. 心率值更新事件

HRS服务及特征成功发现后,设置HRS服务中的Measurement特征属性为Notify,允许HRS设备主动上报Measurement特性,这时可以开始接收HRS设备的心率数据更新了。

处理流程如下图:

image.png

  • 执行GATT Read操作,读取HRS设备的心率数据
  • 蓝牙协议栈上报GATT Notify操作,应用程序接收HRS设备发送的心率数据

3. 例程运行

以CH6121开发板为例,BLE Scanner示例程序的运行步骤为:

  • 连接串口调试工具, 配置为 波特率: 115200, 数据位: 8, 校验位: None, 停止位: 1, 流控: None
  • 开发板拨码开关拨至GND
  • 按RESET按键,复位开发板
  • BLE Scanner开始扫描后,将在串口上输出'scan start'信息
boot_v1.4
[     0.004000][I][INIT    ]Build:Aug  2 2019,20:18:49
[     0.023000][D][MTB     ]mtb find 0x11005000
[     0.042000][I][INIT    ]find 9 partitions
[     0.779000][I][DEMO    ]Bluetooth scanner demo!
[     1.558000][W][AOSBT   ]bt_pub_key_gen:ECC HCI commands not available
[     2.182000][I][DEMO    ]scan start!
  • BLE Scanner发现'YoC HRS'设备并成功连接
[     3.487000][I][DEMO    ]find device YoC HRS
[     3.512000][I][DEMO    ]find device c0:bf:88:e3:3b:cc|(type 1),ADV_CONNECTABLE,02010603030d180809596f4320485253
[     3.559000][I][DEMO    ]Connected, conn handle 0
  • BLE Scanner成功发现HRS服务及特征
[     3.814000][I][DEMO    ]find service HRS, start handle c, end handle 13
[     4.015000][I][DEMO    ]HRS CHAR handle d, val handle e
[     4.116000][I][DEMO    ]HRS DES handle f, UUID 0229
[     4.217000][I][DEMO    ]HRS service discovery complete
  • BLE Scanner打印'GATT notify'表示收到来自HRS设备的心率数据
[     4.418000][I][DEMO    ]GATT write SUCCESS
[     4.520000][I][DEMO    ]GATT notify 008a
[    16.947000][I][DEMO    ]GATT notify 003e
[    17.952000][I][DEMO    ]GATT notify 003f
  • 另一块CH6121开发板运行HRS设备示例程序,发送广播包,设备名为'YoC HRS'
  • HRS设备打印'data'显示间隔1秒刷新一次心率数据
[     0.777000][I][DEMO    ]Bluetooth HRS demo!
[     1.133000][I][DEMO    ]DEV_NAME:YoC HRS
[     2.534000][I][DEMO    ]hrs adv start!
[     2.730000][I][DEMO    ]Connected
[     2.784000][I][DEMO    ]mtu exchange, MTU 247
[     3.565000][D][HRS     ]data:3e
[     4.580000][D][HRS     ]data:3f

HRS设备应用的示例代码请见下回分晓~

原文作者:qinghuan
点击查看原文

Leave a Reply

Your email address will not be published. Required fields are marked *