BLE 开发指南

简介

Quectel FCM242D 和 FGM842D 系列模块支持 QuecOpen® 解决方案。QuecOpen® 是基于 RTOS 系统的嵌入式开发平台。它旨在简化物联网应用的开发和设计。有关 QuecOpen® 的更多信息,请参见 快速入门指南

本文档适用于基于 SDK 构建环境的 QuecOpen® 解决方案。它介绍了 FCM242D 和 FGM842D 系列模块的 BLE API 和开发示例。

BLE API

头文件

ql_ble.h,BLE API 的头文件,在 SDK 的 ql_components/api 目录中。除非另有说明,本文档中提到的所有头文件都在此目录中。

API 概述

API 概述:

函数 描述
ql_ble_address_get() 获取模块的 BLE MAC 地址。
ql_ble_set_notice_cb() 注册 BLE 事件回调函数。
ql_ble_set_adv_param() 设置广播参数。
ql_ble_set_adv_data() 设置广播数据。
ql_ble_set_scan_rsp_data() 设置扫描响应数据。
ql_ble_create_db() 初始化 BLE 并自定义 BLE 服务。
ql_ble_start_advertising() 开始 BLE 广播。
ql_ble_stop_advertising() 停止 BLE 广播。
ql_ble_update_param() 更新连接参数。
ql_ble_set_dev_name() 设置 BLE 设备名称。
ql_ble_start_scaning() 开始 BLE 扫描。
ql_ble_stop_scaning() 停止 BLE 扫描。
ql_ble_set_connect_dev_addr() 设置要连接的 BLE 外围设备 MAC 地址。
ql_ble_start_conn() 发起 BLE 连接。
ql_ble_stop_conn() 停止 BLE 连接。
ql_ble_disconnect() 中央设备或外围设备主动断开与对等设备的连接。
ql_ble_gatt_init() 初始化 GATT 服务并注册 GATT 事件回调函数。
ql_ble_gatts_send_ntf_value() 外围设备通过通知向中央设备发送数据。
ql_ble_gatts_send_ind_value() 外围设备通过指示向中央设备发送数据。
ql_ble_gattc_all_service_discovery() 中央设备发现外围设备的所有服务。
ql_ble_gattc_ntf_ind_enable() 中央设备启用外围设备的通知或指示功能。
ql_ble_gattc_write_data_req_with_handle() 中央设备向外围设备的指定特征值句柄写入数据,并需要外围设备的响应。
ql_ble_gattc_write_data_cmd_with_handle() 中央设备通过命令向外围设备的指定特征值句柄写入数据。
ql_ble_gattc_read_data() 中央设备从外围设备的指定特征值句柄读取数据。
ql_ble_gatt_mtu_changes() 更改 MTU 大小。

API 描述

ql_ble_address_get

此函数获取模块的 BLE MAC 地址。

原型:

ql_ble_errcode_e ql_ble_address_get(uint8_t *mac_addr)

参数:

mac_addr:[出] 模块的 BLE MAC 地址。

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_errcode_e

函数执行结果代码的枚举:

typedef enum
{
    QL_BLE_SUCCESS = 0,
    QL_BLE_ERR_PROFILE,
    QL_BLE_ERR_CREATE_DB,
    QL_BLE_ERR_CMD_NOT_SUPPORT,
    QL_BLE_ERR_UNKNOW_IDX,
    QL_BLE_ERR_BLE_STATUS,
    QL_BLE_ERR_BLE_PARAM,
    QL_BLE_ERR_ADV_DATA,
    QL_BLE_ERR_CMD_RUN,
    QL_BLE_ERR_NO_MEM,
    QL_BLE_ERR_INIT_CREATE,
    QL_BLE_ERR_INIT_STATE,
    QL_BLE_ERR_ATTC_WRITE,
    QL_BLE_ERR_ATTC_WRITE_UNREGISTER,
} ql_ble_errcode_e

成员:

成员 描述
QL_BLE_SUCCESS 执行成功。
QL_BLE_ERR_PROFILE 配置文件错误。
QL_BLE_ERR_CREATE_DB 添加 BLE 服务失败。
QL_BLE_ERR_CMD_NOT_SUPPORT 不支持命令。
QL_BLE_ERR_UNKNOW_IDX 未知 BLE 活动索引。
QL_BLE_ERR_BLE_STATUS BLE 状态错误。
QL_BLE_ERR_BLE_PARAM 参数无效。
QL_BLE_ERR_ADV_DATA 广播数据格式无效。
QL_BLE_ERR_CMD_RUN 执行命令失败。
QL_BLE_ERR_NO_MEM 内存不足。
QL_BLE_ERR_INIT_CREATE 创建连接任务失败。
QL_BLE_ERR_INIT_STATE 连接状态错误。
QL_BLE_ERR_ATTC_WRITE 写入数据失败。
QL_BLE_ERR_ATTC_WRITE_UNREGISTER 要写入数据的 BLE 服务未注册。

ql_ble_set_notice_cb

此函数注册 BLE 事件回调函数。

原型:

ql_ble_errcode_e ql_ble_set_notice_cb(ql_ble_notice_cb callback)

参数:

callback:[入] BLE 事件回调函数。有关详细信息,请参见 ql_ble_notice_cb

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_notice_cb

此函数是 BLE 事件回调函数。

原型:

typedef void (*ql_ble_notice_cb)(ql_ble_notify_e notice, void *param)

参数:

notice:[入] BLE 事件类型。有关详细信息,请参见 ql_ble_notify_e

param:[入] BLE 事件参数。

返回值:

ql_ble_notify_e

BLE 事件类型的枚举:

typedef enum
{
    QL_BLE_STACK_OK = 0,
    QL_BLE_REPORT_ADV_EVENT,
    QL_BLE_MTU_CHANGE_EVENT,
    QL_BLE_CONNECT_EVENT,
    QL_BLE_DISCONNECT_EVENT,
    QL_BLE_INIT_CONNECT_EVENT,
    QL_BLE_ADV_STOP_EVENT,
    QL_BLE_SCAN_STOP_EVENT,
    QL_BLE_CONN_PARAM_UPDATE_EVENT,
    QL_BLE_LINK_RSSI_EVENT,
    QL_BLE_SEC_MASTER_AUTH_REQ,
    QL_BLE_SEC_MASTER_ENCRYPT,
    QL_BLE_SEC_SLAVE_ENCRYPT,
    QL_BLE_BOND_START_EVENT,
    QL_BLE_SEC_PEER_IDENTITY_ADDR,
    QL_BLE_BOND_FAIL_EVENT,
} ql_ble_notify_e;

成员:

成员 描述
QL_BLE_STACK_OK BLE 协议栈已准备就绪。
QL_BLE_REPORT_ADV_EVENT 返回扫描结果。
QL_BLE_MTU_CHANGE_EVENT MTU 已更改。
QL_BLE_CONNECT_EVENT 模块作为外围设备与中央设备建立连接。
QL_BLE_DISCONNECT_EVENT 断开连接事件。
QL_BLE_INIT_CONNECT_EVENT 模块作为中央设备与外围设备建立连接。
QL_BLE_ADV_STOP_EVENT 广播已停止。
QL_BLE_SCAN_STOP_EVENT 扫描已停止。
QL_BLE_CONN_PARAM_UPDATE_EVENT 连接参数已更新。
QL_BLE_LINK_RSSI_EVENT 获取连接链路的 RSSI 值。
QL_BLE_SEC_MASTER_AUTH_REQ 中央设备收到外围设备的认证请求。
QL_BLE_SEC_MASTER_ENCRYPT 中央设备的链路加密。
QL_BLE_SEC_SLAVE_ENCRYPT 外围设备的链路加密。
QL_BLE_BOND_START_EVENT 绑定已开始。
QL_BLE_SEC_PEER_IDENTITY_ADDR 获取对等设备信息。
QL_BLE_BOND_FAIL_EVENT 绑定失败。

ql_ble_set_adv_param

此函数设置广播参数。

原型:

ql_ble_errcode_e ql_ble_set_adv_param(ql_ble_adv_param_t adv_param)

参数:

adv_param

[入] 广播参数。有关详细信息,请参见 ql_ble_adv_param_t

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_adv_param_t

广播参数的结构:

typedef struct
{
    ql_ble_adv_mode_e mode;
    ql_ble_addr_type_e addr_type;
    ql_ble_adv_mac_addr_t peer_addr;
    ql_ble_phy_e phy;
    uint16_t adv_intv_min;
    uint16_t adv_intv_max;
    ql_ble_adv_channel_e channel;
    ql_ble_adv_filter_e filter;
    uint8_t adv_sid;
    uint16_t per_adv_intv_min;
    uint16_t per_adv_intv_max;
    ql_ble_adv_disc_mode_e disc_mode;
} ql_ble_adv_param_t;

参数:

类型 参数 描述
ql_ble_adv_mode_e mode 广播模式。有关详细信息,请参见 ql_ble_adv_mode_e。(目前不支持)
ql_ble_addr_type_e addr_type 广播地址类型。有关详细信息,请参见 ql_ble_addr_type_e。(目前不支持)
ql_ble_adv_mac_addr_t peer_addr 外围设备 MAC 地址。有关详细信息,请参见 ql_ble_adv_mac_addr_t。(目前不支持)
ql_ble_phy_e phy 广播的物理层类型。有关详细信息,请参见 ql_ble_phy_e。(目前不支持)
uint16_t adv_intv_min 最小广播间隔。范围:32–16384。单位:0.625 ms。时间范围:20 ms–10.24 s。
uint16_t adv_intv_max 最大广播间隔。范围:32–16384。单位:0.625 ms。时间范围:20 ms–10.24 s。
ql_ble_adv_channel_e channel 广播通道。有关详细信息,请参见 ql_ble_adv_channel_e
ql_ble_adv_filter_e filter 广播过滤策略。有关详细信息,请参见 ql_ble_adv_filter_e。(目前不支持)
uint8_t adv_sid 广播索引。它仅适用于扩展广播和周期广播。范围:0–0xF。(目前不支持)
uint16_t per_adv_intv_min 外围设备的周期广播最小间隔。范围:32–16384。单位:0.625 ms。时间范围:20 ms–10.24 s。(目前不支持)
uint16_t per_adv_intv_max 外围设备的周期广播最大间隔。范围:32–16384。单位:0.625 ms。时间范围:20 ms–10.24 s。(目前不支持)
ql_ble_adv_disc_mode_e disc_mode 广播发现模式。有关详细信息,请参见 ql_ble_adv_disc_mode_e。(目前不支持)
ql_ble_adv_mode_e

广播模式的枚举:

typedef enum
{
    QL_BLE_ADV_MODE_UNDIRECT = 0x01,
    QL_BLE_ADV_MODE_DIRECT = 0x02,
    QL_BLE_ADV_MODE_NON_CONN_NON_SCAN = 0x03,
    QL_BLE_ADV_MODE_NON_CONN_SCAN = 0x04,
    QL_BLE_ADV_MODE_HDC_DIRECT = 0x05,
    QL_BLE_ADV_MODE_BEACON = 0x06,
    QL_BLE_ADV_MODE_CUSTOM = 0x07,
    QL_BLE_ADV_MODE_EXTEND_CONN_UNDIRECT = 0x11,
    QL_BLE_ADV_MODE_EXTEND_CONN_DIRECT = 0x12,
    QL_BLE_ADV_MODE_EXTEND_NON_CONN_SCAN = 0x13,
    QL_BLE_ADV_MODE_EXTEND_NON_CONN_SCAN_DIRECT = 0x14,
    QL_BLE_ADV_MODE_EXTEND_NON_CONN_NON_SCAN = 0x15,
    QL_BLE_ADV_MODE_EXTEND_NON_CONN_NON_SCAN_DIRECT = 0x16,
    QL_BLE_ADV_MODE_PER_ADV_UNDIRECT = 0x21,
    QL_BLE_ADV_MODE_PER_ADV_DIRECT = 0x22,
} ql_ble_adv_mode_e;

成员:

成员 描述
QL_BLE_ADV_MODE_UNDIRECT 可连接且可扫描的未定向广播。
QL_BLE_ADV_MODE_DIRECT 定向广播。
QL_BLE_ADV_MODE_NON_CONN_NON_SCAN 不可连接且不可扫描的广播。
QL_BLE_ADV_MODE_NON_CONN_SCAN 不可连接但可扫描的广播。
QL_BLE_ADV_MODE_HDC_DIRECT 高占空比可连接定向广播。
QL_BLE_ADV_MODE_BEACON 信标广播。
QL_BLE_ADV_MODE_CUSTOM 自定义类型。
QL_BLE_ADV_MODE_EXTEND_CONN_UNDIRECT 扩展广播模式:可连接且可扫描的未定向广播。
QL_BLE_ADV_MODE_EXTEND_CONN_DIRECT 扩展广播模式:可连接定向广播。
QL_BLE_ADV_MODE_EXTEND_NON_CONN_SCAN 扩展广播模式:不可连接但可扫描的广播。
QL_BLE_ADV_MODE_EXTEND_NON_CONN_SCAN_DIRECT 扩展模式:不可连接且可扫描的定向广播。
QL_BLE_ADV_MODE_EXTEND_NON_CONN_NON_SCAN 扩展广播模式:不可连接且不可扫描的广播。
QL_BLE_ADV_MODE_EXTEND_NON_CONN_NON_SCAN_DIRECT 扩展广播模式:不可连接且不可扫描的定向广播。
QL_BLE_ADV_MODE_PER_ADV_UNDIRECT 周期广播模式:未定向广播。
QL_BLE_ADV_MODE_PER_ADV_DIRECT 周期广播模式:定向广播。
ql_ble_addr_type_e

广播地址类型的枚举:

typedef enum
{
    QL_BLE_ADDR_TYPE_PUBLIC = 0,
    QL_BLE_ADDR_TYPE_PRIVATE,
    QL_BLE_ADDR_TYPE_RANDOM_RESOVABLE,
    QL_BLE_ADDR_TYPE_RANDOM_NONE_RESOVABLE,
} ql_ble_addr_type_e;

成员:

成员 描述
QL_BLE_ADDR_TYPE_PUBLIC 公共地址。
QL_BLE_ADDR_TYPE_PRIVATE 私有地址。
QL_BLE_ADDR_TYPE_RANDOM_RESOVABLE 可解析随机地址。
QL_BLE_ADDR_TYPE_RANDOM_NONE_RESOVABLE 不可解析随机地址。
ql_ble_adv_mac_addr_t

外围设备 MAC 地址的结构:

typedef struct
{
    uint8_t addr[6];
    uint8_t addr_type;
} ql_ble_adv_mac_addr_t;

参数:

类型 参数 描述
uint8_t addr 地址。6 字节数组。
uint8_t addr_type 地址类型。0 公共地址 1 私有随机地址
ql_ble_phy_e

广播物理层类型的枚举:

typedef enum
{
    QL_BLE_PHY_ANY = 0,
    QL_BLE_PHY_1MBPS = 1,
    QL_BLE_PHY_2MBPS = 2,
    QL_BLE_PHY_CODED = 3,
} ql_ble_phy_e;

成员:

成员 描述
QL_BLE_PHY_ANY 任意类型。
QL_BLE_PHY_1MBPS 1 Mbps 传输速率。
QL_BLE_PHY_2MBPS 2 Mbps 传输速率。
QL_BLE_PHY_CODED 编码类型。
ql_ble_adv_channel_e

广播通道的枚举:

typedef enum
{
    QL_BLE_ADV_CHAN_37 = 0x01,
    QL_BLE_ADV_CHAN_38 = 0x02,
    QL_BLE_ADV_CHAN_39 = 0x04,
    QL_BLE_ADV_CHAN_ALL = 0X07,
} ql_ble_adv_channel_e;

成员:

成员 描述
QL_BLE_ADV_CHAN_37 通道 37。
QL_BLE_ADV_CHAN_38 通道 38。
QL_BLE_ADV_CHAN_39 通道 39。
QL_BLE_ADV_CHAN_ALL 所有通道。
ql_ble_adv_filter_e

广播过滤策略的枚举:

typedef enum
{
    QL_BLE_ADV_ALLOW_SCAN_ANY_CON_ANY = 0x00,
    QL_BLE_ADV_ALLOW_SCAN_WLST_CON_ANY = 0x01,
    QL_BLE_ADV_ALLOW_SCAN_ANY_CON_WLST = 0x02,
    QL_BLE_ADV_ALLOW_SCAN_WLST_CON_WLST = 0x03,
} ql_ble_adv_filter_e;

成员:

成员 描述
QL_BLE_ADV_ALLOW_SCAN_ANY_CON_ANY 任何设备都可以扫描和连接本地设备。
QL_BLE_ADV_ALLOW_SCAN_WLST_CON_ANY 任何设备都可以连接本地设备,但只有白名单中的设备可以扫描本地设备。
QL_BLE_ADV_ALLOW_SCAN_ANY_CON_WLST 任何设备都可以扫描本地设备,但只有白名单中的设备可以连接本地设备。
QL_BLE_ADV_ALLOW_SCAN_WLST_CON_WLST 只有白名单中的设备可以扫描和连接本地设备。
ql_ble_adv_disc_mode_e

广播发现模式的枚举:

typedef enum
{
    QL_BLE_ADV_DISC_MODE_GEN_DISC = 0,
    QL_BLE_ADV_DISC_MODE_LIM_DISC = 1,
    QL_BLE_ADV_DISC_MODE_NON_DISC = 2,
    QL_BLE_ADV_DISC_MODE_MAX = 3,
} ql_ble_adv_disc_mode_e;

成员:

成员 描述
QL_BLE_ADV_DISC_MODE_GEN_DISC 通用发现模式。
QL_BLE_ADV_DISC_MODE_LIM_DISC 有限发现模式。
QL_BLE_ADV_DISC_MODE_NON_DISC 非发现模式。

ql_ble_set_adv_data

此函数设置广播数据。

原型:

ql_ble_errcode_e ql_ble_set_adv_data(uint8_t *adv_buff, uint16_t adv_len)

参数:

adv_buff

[入] 广播数据,应根据 BLE 广播数据规则编写。

adv_len

[入] 广播数据的长度。单位:字节。

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_set_scan_rsp_data

此函数设置扫描响应数据。

原型:

ql_ble_errcode_e ql_ble_set_scan_rsp_data(uint8_t *scan_rsp, uint16_t scan_rsp_len)

参数:

scan_rsp

[入] 扫描响应数据,应根据 BLE 广播数据规则编写。

scan_rsp_len

[入] 扫描响应数据的长度。单位:字节。

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_create_db

此函数初始化 BLE 并自定义 BLE 服务。

原型:

ql_ble_errcode_e ql_ble_create_db(ql_ble_gatt_service_t *service, uint8_t *svc_id)

参数:

service

[入] BLE 服务列表。有关详细信息,请参见 ql_ble_gatt_service_t

svc_id

[入] BLE 服务 ID。(目前不支持)

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_gatt_service_t

BLE 服务列表的结构:

typedef struct
{
    uint16_t prf_task_id;
    uint8_t uuid[16];
    uint8_t att_db_nb;
    uint16_t start_hdl;
    ql_ble_attm_desc_t* att_db;
    uint8_t svc_perm;
}ql_ble_gatt_service_t;

参数:

类型 参数 描述
uint16_t prf_task_id BLE 服务 ID。
uint8_t uuid BLE 服务 UUID。
uint8_t att_db_nb 属性数据库数量。
uint16_t start_hdl 服务起始句柄。
ql_ble_attm_desc_t att_db BLE 服务属性数据库。有关详细信息,请参见 ql_ble_attm_desc_t
uint8_t svc_perm BLE 服务配置。
ql_ble_attm_desc_t

BLE 服务属性数据库的结构:

typedef struct
{
    uint8_t uuid[16];
    uint16_t info;
    uint16_t ext_info;
}ql_ble_attm_desc_t

参数:

类型 参数 描述
uint8_t uuid 属性 UUID。
uint16_t info 属性信息。
uint16_t ext_info 扩展属性信息。

ql_ble_start_advertising

此函数开始 BLE 广播。

原型:

ql_ble_errcode_e ql_ble_start_advertising(uint16_t duration)

参数:

duration

[入] 广播持续时间。单位:10 ms。0 表示不主动停止广播。

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_stop_advertising

此函数停止 BLE 广播。

原型:

ql_ble_errcode_e ql_ble_stop_advertising(void)

参数:

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_update_param

此函数更新连接参数。

原型:

ql_ble_errcode_e ql_ble_update_param(uint8_t conn_idx, uint16_t intv_min, uint16_t intv_max, uint16_t latency, uint16_t sup_to)

参数:

conn_idx

[入] 连接索引。

intv_min

[入] 最小连接间隔。范围:6–3200。单位:1.25 ms。时间范围:7.5 ms–4 s。

intv_max

[入] 最大连接间隔。范围:6–3200。单位:1.25 ms。时间范围:7.5 ms–4 s。

latency

[入] 外围设备上可忽略的连接间隔数量。它必须符合 (1 + latency) × intv_max × 2 × 1.25 < sup_to × 10。

sup_to

[入] 连接超时周期。范围:10–3200。单位:10 ms。时间范围:100 ms–32 s。

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_set_dev_name

此函数设置 BLE 设备名称。

原型:

ql_ble_errcode_e ql_ble_set_dev_name(uint8_t *name , uint8_t name_len)

参数:

name

[入] BLE 设备名称。

name_len

[入] BLE 设备名称的长度。最大值:18 字节。

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_start_scaning

此函数开始 BLE 扫描。

原型:

ql_ble_errcode_e ql_ble_start_scaning(ql_ble_scan_param_t scan_param)

参数:

scan_param

[入] 扫描参数。有关详细信息,请参见 ql_ble_scan_param_t

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_scan_param_t

扫描参数的结构:

typedef struct
{
    ql_ble_scan_mode_e scan_mode;
    ql_ble_phy_e phy;
    uint8_t dup_filt;
    uint16_t scan_intv;
    uint16_t scan_wd;
}ql_ble_scan_param_t

参数:

类型 参数 描述
ql_ble_scan_mode_e scan_mode 扫描模式。有关详细信息,请参见 ql_ble_scan_mode_e
ql_ble_phy_e phy 广播的物理层类型。有关详细信息,请参见 ql_ble_phy_e
uint8_t dup_filt 重复数据包过滤策略。
uint16_t scan_intv 扫描间隔。单位:0.626 ms。
uint16_t scan_wd 扫描窗口。单位:0.626 ms。
ql_ble_scan_mode_e

扫描模式的枚举:

typedef enum
{
    QL_BLE_SCAN_MODE_GEN_DISC = 0,
    QL_BLE_SCAN_MODE_OBSERVER = 1,
    QL_BLE_SCAN_MODE_MAX = 3,
} ql_ble_scan_mode_e;

成员:

成员 描述
QL_BLE_SCAN_MODE_GEN_DISC 通用发现模式。
QL_BLE_SCAN_MODE_OBSERVER 观察者模式。

ql_ble_stop_scaning

此函数停止 BLE 扫描。

原型:

ql_ble_errcode_e ql_ble_stop_scaning(void)

参数:

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_set_connect_dev_addr

此函数设置要连接的 BLE 外围设备 MAC 地址。

原型:

ql_ble_errcode_e ql_ble_set_connect_dev_addr(ql_ble_adv_mac_addr_t *addr)

参数:

addr

[入] 要连接的外围设备 MAC 地址。有关详细信息,请参见 ql_ble_adv_mac_addr_t

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_start_conn

此函数发起 BLE 连接。

原型:

ql_ble_errcode_e ql_ble_start_conn(uint16_t intv_min,uint16_t intv_max,uint16_t latency, uint16_t sup_to)

参数:

intv_min

[入] 最小连接间隔。范围:6–3200。单位:1.25 ms。时间范围:7.5 ms–4 s。

intv_max

[入] 最大连接间隔。范围:6–3200。单位:1.25 ms。时间范围:7.5 ms–4 s。

latency

[入] 外围设备上可忽略的连接间隔数量。它必须符合 (1 + latency) × intv_max × 2 × 1.25 < sup_to × 10。

sup_to

[入] 连接超时周期。范围:10–3200。单位:10 ms。时间范围:100 ms–32 s。

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_stop_conn

此函数停止 BLE 连接。

原型:

ql_ble_errcode_e ql_ble_stop_conn(void)

参数:

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_disconnect

此函数由中央设备或外围设备主动断开与对等设备的连接。

原型:

ql_ble_errcode_e ql_ble_disconnect(uint8_t conn_idx)

参数:

conn_idx

[入] 连接索引。

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_gatt_init

此函数初始化 GATT 服务并注册 GATT 事件回调函数。

原型:

ql_ble_errcode_e ql_ble_gatt_init(ql_ble_gatt_msg_handler_t gatt_evt)

参数:

gatt_evt

[入] GATT 事件回调函数。有关详细信息,请参见 ql_ble_gatt_msg_handler_t

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_gatt_msg_handler_t

此函数是 GATT 事件回调函数。

原型:

typedef uint16_t (*ql_ble_gatt_msg_handler_t)(ql_ble_gatt_msg_t *p_msg)

参数:

p_msg

[入] GATT 事件。有关详细信息,请参见 ql_ble_gatt_msg_t

返回值:

返回 uint16 类型的值,目前没有具体含义。

ql_ble_gatt_msg_t

GATT 事件的结构:

typedef struct
{
    ql_ble_gatt_msg_evt_t msg_evt;
    uint8_t conn_idx;
    union
    {
        ql_ble_gatt_data_report report;
        ql_ble_gatt_op_cmp_t op;
        ql_ble_gatt_svc_disc_s svc_disc;
        ql_ble_gatt_svc_inc_s svc_inc;
        ql_ble_gatt_char_disc_s char_disc;
        ql_ble_gatt_desc_disc_s desc_disc;
    } param;
}ql_ble_gatt_msg_t

参数:

类型 参数 描述
ql_ble_gatt_msg_evt_t msg_evt GATT 事件类型。有关详细信息,请参见 ql_ble_gatt_msg_evt_t
uint8_t conn_idx 连接索引。
ql_ble_gatt_data_report report GATT 数据报告。有关详细信息,请参见 ql_ble_gatt_data_report
ql_ble_gatt_op_cmp_t op GATT 操作类型,包括读取、写入、通知和指示。有关详细信息,请参见 ql_ble_gatt_op_cmp_t
ql_ble_gatt_svc_disc_s svc_disc 发现所有服务。有关详细信息,请参见 ql_ble_gatt_svc_disc_s
ql_ble_gatt_svc_inc_s svc_inc 根据 UUID 发现包含的服务。有关详细信息,请参见 ql_ble_gatt_svc_inc_s
ql_ble_gatt_char_disc_s char_disc 特征发现。有关详细信息,请参见 ql_ble_gatt_char_disc_s
ql_ble_gatt_desc_disc_s desc_disc 特征描述符发现。有关详细信息,请参见 ql_ble_gatt_desc_disc_s
ql_ble_gatt_msg_evt_t

GATT 事件类型的枚举:

typedef enum
{
    QL_BLE_GATT_MSG_READ_REQ,
    QL_BLE_GATT_MSG_WRITE_REQ,
    QL_BLE_GATT_MSG_ATT_INFO_REQ,
    QL_BLE_GATT_MSG_NTF_REQ,

    QL_BLE_GATT_MSG_IND_REQ,
    QL_BLE_GATT_MSG_READ_IND,
    QL_BLE_GATT_MSG_CMP_EVT,
    QL_BLE_GATT_MSG_LINK_CREATE,
    QL_BLE_GATT_MSG_LINK_LOST,
    QL_BLE_GATT_MSG_DISC_SVC,
    QL_BLE_GATT_MSG_DISC_SVC_INC,
    QL_BLE_GATT_MSG_DISC_CHAR,
    QL_BLE_GATT_MSG_DISC_CHAR_DESC,
    QL_BLE_GATT_MSG_HANDLE_ERROR = 0x80,
} ql_ble_gatt_msg_evt_t;

成员:

成员 描述
QL_BLE_GATT_MSG_READ_REQ 读取数据请求。
QL_BLE_GATT_MSG_WRITE_REQ 写入数据请求。
QL_BLE_GATT_MSG_ATT_INFO_REQ 属性信息请求。
QL_BLE_GATT_MSG_NTF_REQ 从 GATT 外围设备接收的通知数据。
QL_BLE_GATT_MSG_IND_REQ 从 GATT 外围设备接收的指示数据。
QL_BLE_GATT_MSG_READ_IND 读取请求响应。
QL_BLE_GATT_MSG_CMP_EVT 操作完成事件。
QL_BLE_GATT_MSG_LINK_CREATE 链路已创建。
QL_BLE_GATT_MSG_LINK_LOST 链路已丢失。
QL_BLE_GATT_MSG_DISC_SVC 所有服务已发现。
QL_BLE_GATT_MSG_DISC_SVC_INC 包含的服务已发现。
QL_BLE_GATT_MSG_DISC_CHAR 特征已发现。
QL_BLE_GATT_MSG_DISC_CHAR_DESC 特征描述符已发现。
QL_BLE_GATT_MSG_HANDLE_ERROR GATT 消息处理错误。
ql_ble_gatt_data_report

GATT 数据报告的结构:

typedef struct
{
    uint8_t svc_id;
    uint16_t att_idx;
    uint16_t char_handle;
    ql_ble_data_t data;
} ql_ble_gatt_data_report

参数:

类型 参数 描述
uint8_t svc_id BLE 服务 ID。
uint16_t att_idx 服务表中的属性索引。
uint16_t char_handle 外围设备服务中的属性句柄号。
ql_ble_data_t data 数据。有关详细信息,请参见 ql_ble_data_t
ql_ble_data_t

数据结构定义如下:

typedef struct
{
    uint16_t len;
    uint8_t *data;
} ql_ble_data_t

参数:

类型 参数 描述
uint16_t len 数据长度。单位:字节。
uint8_t data 数据内容。
ql_ble_gatt_op_cmp_t

GATT 操作类型的结构:

typedef struct
{
    ql_ble_gatt_operation operation;
    uint8_t status;
    void *arg;
}ql_ble_gatt_op_cmp_t

参数:

类型 参数 描述
ql_ble_gatt_operation operation GATT 操作类型。有关详细信息,请参见 ql_ble_gatt_operation
uint8_t status 操作状态。
void *arg 参数指针。
ql_ble_gatt_operation

GATT 操作类型的枚举:

typedef enum
{
    QL_BLE_GATT_OP_NONE,
    QL_BLE_GATT_OP_NOTIFY,
    QL_BLE_GATT_OP_INDICATION,
    QL_BLE_GATT_OP_WRITE_REQ,
    QL_BLE_GATT_OP_WRITE_CMD,
    QL_BLE_GATT_OP_READ,
    QL_BLE_GATT_OP_PEER_SVC_DISC_END,
} ql_ble_gatt_operation;

成员:

成员 描述
QL_BLE_GATT_OP_NONE 无操作
QL_BLE_GATT_OP_NOTIFY 通知
QL_BLE_GATT_OP_INDICATION 指示
QL_BLE_GATT_OP_WRITE_REQ 写入请求
QL_BLE_GATT_OP_WRITE_CMD 写入命令
QL_BLE_GATT_OP_READ 读取
QL_BLE_GATT_OP_PEER_SVC_DISC_END 完成对等设备服务的发现
ql_ble_gatt_svc_disc_s

所有服务发现的结构:

typedef struct
{
    uint8_t uuid_len;
    uint8_t uuid[16];
    uint16_t start_hdl;
    uint16_t end_hdl;
}ql_ble_gatt_svc_disc_s

参数:

类型 参数 描述
uint8_t uuid_len 服务 UUID 长度。单位:字节。
uint8_t uuid 服务 UUID。
uint16_t start_hdl 服务起始句柄。
uint16_t end_hdl 服务结束句柄。
ql_ble_gatt_svc_inc_s

根据 UUID 发现包含服务的结构:

typedef struct
{
    uint8_t uuid_len;
    uint8_t uuid[16];
    uint16_t start_hdl;
    uint16_t end_hdl;
}ql_ble_gatt_svc_inc_s

参数:

类型 参数 描述
uint8_t uuid_len 服务 UUID 长度。单位:字节。
uint8_t uuid 服务 UUID。
uint16_t start_hdl 服务起始句柄。
uint16_t end_hdl 服务结束句柄。
ql_ble_gatt_char_disc_s

特征发现的结构:

typedef struct
{
    uint8_t uuid_len;
    uint8_t uuid[16];
    uint16_t handle;
    ql_ble_gatt_prop_e prop;
}ql_ble_gatt_char_disc_s

参数:

类型 参数 描述
uint8_t uuid_len 特征 UUID 长度。单位:字节。
uint8_t uuid 特征 UUID。
uint16_t handle 特征值句柄。
ql_ble_gatt_prop_e prop GATT 特征属性。有关详细信息,请参见 ql_ble_gatt_prop_e
ql_ble_gatt_prop_e

GATT 特征属性的枚举:

typedef enum
{
    QL_BLE_GATT_PROP_BROADCAST = 0x01,
    QL_BLE_GATT_PROP_READ = 0x02,
    QL_BLE_GATT_PROP_WRITE_CMD = 0x04,
    QL_BLE_GATT_PROP_WRITE = 0x08,
    QL_BLE_GATT_PROP_NOTIFY = 0x10,
    QL_BLE_GATT_PROP_INDICATE = 0x20,
    QL_BLE_GATT_PROP_WRITE_SIGNED = 0x40,
    QL_BLE_GATT_PROP_EXTENDED = 0x80,
} ql_ble_gatt_prop_e;

成员:

成员 描述
QL_BLE_GATT_PROP_BROADCAST 广播属性
QL_BLE_GATT_PROP_READ 读取属性
QL_BLE_GATT_PROP_WRITE_CMD 无响应写入
QL_BLE_GATT_PROP_WRITE 写入
QL_BLE_GATT_PROP_NOTIFY 通知
QL_BLE_GATT_PROP_INDICATE 指示
QL_BLE_GATT_PROP_WRITE_SIGNED 认证签名写入
QL_BLE_GATT_PROP_EXTENDED 扩展属性
ql_ble_gatt_desc_disc_s

特征描述符发现的结构:

typedef struct
{
    uint8_t uuid_len;
    uint8_t uuid[16];
    uint16_t handle;
} ql_ble_gatt_desc_disc_s;

参数:

类型 参数 描述
uint8_t uuid_len 特征描述符 UUID 长度。单位:字节。
uint8_t uuid 特征描述符 UUID。
uint16_t handle 句柄。

ql_ble_gatts_send_ntf_value

此函数由外围设备(即模块)通过通知向中央设备发送数据。

原型:

ql_ble_errcode_e ql_ble_gatts_send_ntf_value(uint8_t conn_idx, uint8_t svc_id, uint8_t att_idx, uint8_t *data, uint16_t len)

参数:

conn_idx

[入] 连接索引。

svc_id

[入] BLE 服务 ID。

att_idx

[入] 服务列表中的属性索引。

data

[入] 要发送的数据。

len

[入] 数据长度。单位:字节。

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_gatts_send_ind_value

此函数由外围设备(即模块)通过指示向中央设备发送数据。

原型:

ql_ble_errcode_e ql_ble_gatts_send_ind_value(uint8_t conn_idx, uint8_t svc_id, uint8_t att_idx, uint8_t *data, uint16_t len)

参数:

conn_idx

[入] 连接索引。

svc_id

[入] BLE 服务 ID。

att_idx

[入] 服务列表中的属性索引。

data

[入] 要发送的数据。

len

[入] 数据长度。单位:字节。

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_gattc_all_service_discovery

此函数由中央设备(即模块)发现外围设备的所有服务。

原型:

ql_ble_errcode_e ql_ble_gattc_all_service_discovery( uint8_t conn_idx)

参数:

conn_idx

[入] 连接索引。

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_gattc_ntf_ind_enable

此函数由中央设备(即模块)启用外围设备的通知或指示功能。

原型:

ql_ble_errcode_e ql_ble_gattc_ntf_ind_enable(uint8_t conn_idx , uint16_t handle , bool ntf , bool ind)

参数:

conn_idx

[入] 连接索引。

handle

[入] 服务列表中的属性句柄。

ntf

[入] 是否启用通知。

0 禁用

1 启用

ind

[入] 是否启用指示。

0 禁用

1 启用

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_gattc_write_data_req_with_handle

此函数由中央设备(即模块)向外围设备的指定特征值句柄写入数据,并需要外围设备的响应。

原型:

ql_ble_errcode_e ql_ble_gattc_write_data_req_with_handle(uint8_t conn_idx,uint16_t handle,uint8_t *data,uint16_t data_len)

参数:

conn_idx

[入] 连接索引。

handle

[入] 外围设备特征值句柄。

data

[入] 要写入的数据。

data_len

[入] 数据长度。单位:字节。

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_gattc_write_data_cmd_with_handle

此函数由中央设备(即模块)通过命令向外围设备的指定特征值句柄写入数据。

原型:

ql_ble_errcode_e ql_ble_gattc_write_data_cmd_with_handle(uint8_t conn_idx,uint16_t handle, uint8_t *data,uint16_t data_len)

参数:

conn_idx

[入] 连接索引。

handle

[入] 外围设备特征值句柄。

data

[入] 要写入的数据。

data_len

[入] 数据长度。单位:字节。

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_gattc_read_data

此函数由中央设备(即模块)从外围设备的指定特征值句柄读取数据。

原型:

ql_ble_errcode_e ql_ble_gattc_read_data(uint8_t conn_idx, uint16_t handle)

参数:

conn_idx

[入] 连接索引。

handle

[入] 外围设备特征值句柄。

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

ql_ble_gatt_mtu_changes

此函数更改 MTU 大小。

原型:

ql_ble_errcode_e ql_ble_gatt_mtu_changes(uint8_t conn_idx, uint16_t mtu_size)

参数:

conn_idx

[入] 连接索引。

mtu_size

[入] 更新的 MTU 值。最大值:512。单位:字节。

返回值:

函数执行结果代码。有关详细信息,请参见 ql_ble_errcode_e

示例

本章描述如何使用上述 BLE API 以及如何调试应用程序的 BLE 数据发送和接收功能示例。

BLE API 的外围设备和中央设备功能示例位于 ql_applicationexampleble_demoql_ble_demo.c 目录中,您可以在其中查看 BLE API 的完整示例。

模块作为 BLE 外围设备

  1. 初始化 BLE 外围设备。示例代码如下:

    // ...
    
    static void ql_ble_demo_entry(void *arg)
    {
        ql_ble_demo_msg ble_demo_msg;
        uint8_t ble_mac[6] = {0};
    
        ql_ble_address_get(ble_mac);
        os_printf("ble_mac: [%02x:%02x:%02x:%02x:%02x:%02x] rn",
                ble_mac[0], ble_mac[1], ble_mac[2], ble_mac[3], ble_mac[4], ble_mac[5]);
    
        /* 设置 ble 事件回调 */
        ql_ble_set_notice_cb(ql_ble_demo_gap_cb);
        ql_ble_gatt_init(ql_ble_demo_gatt_cb);
    
        while (1)
        {
            os_memset((void *)&ble_demo_msg, 0x00, sizeof(ql_ble_demo_msg));
            if (ql_rtos_queue_wait(ql_ble_demo_q, (uint8 *)&ble_demo_msg, sizeof(ble_demo_msg), QL_WAIT_FOREVER) == 0)
            {
                ql_ble_demo_msg_process(&ble_demo_msg);
            }
        }
    }
    
  2. 添加 BLE 服务并设置广播参数。示例代码如下:

    uint8_t svc_uuid[16] = {0x36, 0xF5, 0, 0, 0x34, 0x56, 0, 0, 0, 0, 0x28, 0x37, 0, 0, 0, 0};
    
    ql_ble_gatt_service_t service = {0};
    service.prf_task_id = 0;
    service.att_db_nb = QL_BLE_DEMO_IDX_NB;
    service.start_hdl = 0;
    service.att_db = ql_ble_demo_profile_db;
    service.svc_perm = QL_PERM_SET(SVC_UUID_LEN, UUID_128);
    memcpy((void *)&service.uuid[0], (const void *)&svc_uuid[0], 16);
    
    ret = ql_ble_create_db(&service, 0);
    if (ret != QL_BLE_SUCCESS)
    {
        os_printf("ql_ble_create_db, ret: [%d] rn", ret);
        return;
    }
    
    ql_ble_adv_param_t adv_param = {0};
    adv_param.adv_intv_min = 160;
    adv_param.adv_intv_max = 160;
    adv_param.channel = QL_BLE_ADV_CHAN_ALL;
    
    ret = ql_ble_set_adv_param(adv_param);
    if (ret != QL_BLE_SUCCESS)
    {
        os_printf("ql_ble_set_adv_param, ret: [%d] rn", ret);
        return;
    }
    
  3. 配置广播数据、扫描响应数据并开始广播。示例代码如下:

    uint8_t adv_data[31] = {0};
    adv_data[0] = 0x03;
    adv_data[1] = 0xFF;
    adv_data[2] = 0x31;
    adv_data[3] = 0x32;
    
    ret = ql_ble_set_adv_data(&adv_data[0], 4);
    if (ret != QL_BLE_SUCCESS)
    {
        os_printf("ql_ble_set_adv_data, ret: [%d] rn", ret);
        return;
    }
    
    uint8_t scan_rsp_data[31] = {0};
    uint8_t len = 0;
    len = snprintf((char *)&scan_rsp_data[2], sizeof(scan_rsp_data) - 1, "FGM842D");
    scan_rsp_data[0] = len + 1;
    scan_rsp_data[1] = 0x09;
    
    ret = ql_ble_set_scan_rsp_data(&scan_rsp_data[0], len + 2);
    if (ret != QL_BLE_SUCCESS)
    {
        os_printf("ql_ble_set_scan_rsp_data, ret: [%d] rn", ret);
        return;
    }
    
    ret = ql_ble_start_advertising(0);
    if (ret != QL_BLE_SUCCESS)
    {
        os_printf("ql_ble_start_advertising, ret: [%d] rn", ret);
        return;
    }
    
  4. 打开手机上的 nRF Connect 应用程序。点击“SCAN”以扫描外围设备,在扫描结果中选择“FGM842D”,然后点击“CONNECT”。

    连接设备

    模块成功连接后,“CLIENT”中会显示以下信息:

    连接成功

    1. 通过 nRF Connect 应用程序向模块发送数据。模块接收数据并将数据发送回 nRF Connect 应用程序。

    i. 选择可编辑的特征值,然后单击上箭头。

    编辑特征值

    ii. 以文本格式输入要发送的数据,然后单击“SEND”。

    BLE 连接示例

    iii. 模块接收数据后,将数据发送回 nRF Connect,如下图所示。

    发送数据回

    接收和发送回数据的代码示例如下:

    uint16_t ql_ble_demo_gatt_cb(ql_ble_gatt_msg_t *p_msg)
    {
        os_printf("%s, msg_evt: [%d], conn_idx: [%d] rn", __func__, p_msg->msg_evt, p_msg->conn_idx);
        uint8_t idx = 0;
    
        switch (p_msg->msg_evt)
        {
            case QL_BLE_GATT_MSG_WRITE_REQ:
            {
                os_printf("conn_idx: [%d], svc_id: [%d], att_idx: [%d], handle: [%d], len: [%d], data: [%s] rn",
                        p_msg->conn_idx, p_msg->param.report.svc_id, p_msg->param.report.att_idx, 
                        p_msg->param.report.char_handle, p_msg->param.report.data.len, p_msg->param.report.data.data);
    
                ql_ble_demo_msg ble_demo_msg = {0};
                ble_demo_msg.msg_id = QL_BLE_DEMO_PER_GATT_SEND_NTF;
                ble_demo_msg.msg_param.send_ntf.con_idx = p_msg->conn_idx;
                ble_demo_msg.msg_param.send_ntf.svc_id = p_msg->param.report.svc_id;
                ble_demo_msg.msg_param.send_ntf.att_idx = p_msg->param.report.att_idx;
                ble_demo_msg.msg_param.send_ntf.len = p_msg->param.report.data.len;
                ble_demo_msg.msg_param.send_ntf.data = malloc(p_msg->param.report.data.len);
                memset((void *)ble_demo_msg.msg_param.send_ntf.data, 0x00, p_msg->param.report.data.len);
                memcpy((void *)ble_demo_msg.msg_param.send_ntf.data, (const void *)p_msg->param.report.data.data, 
                    p_msg->param.report.data.len);
                ql_ble_demo_msg_send(&ble_demo_msg);
                break;
            }
        }
    }
    
    // ...
    
    static void ql_ble_demo_msg_process(ql_ble_demo_msg *ble_msg)
    {
        os_printf("msg_id: %d rn", ble_msg->msg_id);
    
        switch (ble_msg->msg_id)
        {
            case QL_BLE_DEMO_PER_GATT_SEND_NTF:
            {
                ql_ble_gatts_send_ntf_value(ble_msg->msg_param.send_ntf.con_idx,
                                            ble_msg->msg_param.send_ntf.svc_id,
                                            ble_msg->msg_param.send_ntf.att_idx,
                                            ble_msg->msg_param.send_ntf.data,
                                            ble_msg->msg_param.send_ntf.len);
                if (ble_msg->msg_param.send_ntf.data != NULL)
                {
                    free(ble_msg->msg_param.send_ntf.data);
                    ble_demo_msg.msg_param.send_ntf.data = NULL;
                }
                break;
            }
        }
    }
    

模块作为 BLE中央设备

在此示例中,nRF Connect 应用程序用作外围设备进行测试。

  1. 初始化 BLE 中央设备。代码示例如下:

    // ...
    
    static void ql_ble_demo_entry(void *arg)
    {
        ql_ble_demo_msg ble_demo_msg;
        uint8_t ble_mac[6] = {0};
    
        ql_ble_address_get(ble_mac);
        os_printf("ble_mac: [%02x:%02x:%02x:%02x:%02x:%02x] rn",
                ble_mac[0], ble_mac[1], ble_mac[2], ble_mac[3], ble_mac[4], ble_mac[5]);
    
        /* 设置 ble 事件回调 */
        ql_ble_set_notice_cb(ql_ble_demo_gap_cb);
        ql_ble_gatt_init(ql_ble_demo_gatt_cb);
    
        while (1)
        {
            os_memset((void *)&ble_demo_msg, 0x00, sizeof(ql_ble_demo_msg));
            if (ql_rtos_queue_wait(ql_ble_demo_q, (uint8 *)&ble_demo_msg, sizeof(ble_demo_msg), QL_WAIT_FOREVER) == 0)
            {
                ql_ble_demo_msg_process(&ble_demo_msg);
            }
        }
    }
    
  2. 设置扫描参数并开始扫描。代码示例如下:

    // ...
    
    case QL_BLE_DEMO_START_SCAN:
    {
        ql_ble_scan_param_t scan_param = {0};
        scan_param.scan_intv = 0x50;
        scan_param.scan_wd = 0x20;
    
        ret = ql_ble_start_scaning(scan_param);
        if (ret != QL_BLE_SUCCESS)
        {
            os_printf("ql_ble_start_scaning, ret: [%d] rn", ret);
            return;
        }
        break;
    }
    
  3. 扫描开始后,将生成 QL_BLE_REPORT_ADV_EVENT 事件以选择要连接的外围设备。

    // ...
    
    case QL_BLE_REPORT_ADV_EVENT:
    {
        ql_ble_recv_adv_t *recv_adv = (ql_ble_recv_adv_t *)param;
        os_printf("adv_type: [%d], adv_addr_type: [%d], adv_addr:[%02x:%02x:%02x:%02x:%02x:%02x], rssi: [%d] rn",
                recv_adv->adv_type, recv_adv->adv_addr_type, recv_adv->adv_addr[0], recv_adv->adv_addr[1], 
                recv_adv->adv_addr[2], recv_adv->adv_addr[3], recv_adv->adv_addr[4], recv_adv->adv_addr[5], 
                recv_adv->rssi);
    
    #if CFG_ENABLE_QUECTEL_BLE_CENTRAL
        ql_ble_demo_report_adv_deal(recv_adv);
    #endif
        break;
    }
    
    // ...
    
    void ql_ble_demo_report_adv_deal(ql_ble_recv_adv_t *p_adv_report)
    {
        uint8_t index = 0;
    
        while (index < p_adv_report->data_len)
        {
            gapAdStructure_t adElement;
            adElement.length = p_adv_report->data[index];
            adElement.adType = p_adv_report->data[index + 1];
            adElement.aData = (uint8_t *)&p_adv_report->data[index + 2];
    
            if ((adElement.adType = 0x08) || (adElement.adType = 0x09))
            {
                if (!memcmp(adElement.aData, "phone_server", strlen("phone_server"))) // check adv name
                {
                    os_printf("Found Device NAME, RSSI:%ddBm, mac:", p_adv_report->rssi);
                    for (uint8_t i = 0; i < 6; i++)
                    {
                        os_printf("%02X ", p_adv_report->adv_addr[i]);
                    }
                    os_printf("rn");
    
                    memcpy(&peer_addr.addr[0], p_adv_report->adv_addr, 6);
                    peer_addr.addr_type = p_adv_report->adv_addr_type;
    
                    ql_ble_demo_msg ble_demo_msg = {0};
                    ble_demo_msg.msg_id = QL_BLE_DEMO_STOP_SCAN;
                    ql_ble_demo_msg_send(&ble_demo_msg);
                    return;
                }
            }
    
            /* Move on to the next AD element type */
            index += adElement.length + sizeof(uint8_t);
        }
    }
    
  4. 连接外围设备后,将生成 QL_BLE_INIT_CONNECT_EVENT 事件以发现外围设备的服务。

    // ...
    
    case QL_BLE_DEMO_STOP_SCAN:
    {
        ret = ql_ble_stop_scaning();
        if (ret != QL_BLE_SUCCESS)
        {
            os_printf("ql_ble_stop_scaning, ret: [%d] rn", ret);
            return;
        }
    
        if (ql_ble_demo_sem)
        {
            ql_rtos_semaphore_wait(ql_ble_demo_sem, QL_BLE_DEMO_TIMEOUT_MS);
        }
    
        ql_ble_set_connect_dev_addr(&peer_addr);
        ret = ql_ble_start_conn(0x30, 0x30, 0, 500);
        if (ret != QL_BLE_SUCCESS)
        {
            os_printf("ql_ble_start_conn, ret: [%d] rn", ret);
            return;
        }
        break;
    }
    
    // ...
    
    case QL_BLE_INIT_CONNECT_EVENT:
    {
        ql_ble_conn_ind_t *conn_ind = (ql_ble_conn_ind_t *)param;
        os_printf("conn_idx: [%d], addr_type: [%d], peer_addr: [%02x:%02x:%02x:%02x:%02x:%02x] rn",
                conn_ind->conn_idx, conn_ind->peer_addr_type, conn_ind->peer_addr[0], conn_ind->peer_addr[1],
                conn_ind->peer_addr[2], conn_ind->peer_addr[3], conn_ind->peer_addr[4], conn_ind->peer_addr[5]);
    
        conn_hdl = conn_ind->conn_idx;
    
    #if CFG_ENABLE_QUECTEL_BLE_CENTRAL
        ql_ble_demo_msg ble_demo_msg = {0};
        ble_demo_msg.msg_id = QL_BLE_DEMO_CENTRAL_EXCHANGE_MTU;
        ql_ble_demo_msg_send(&ble_demo_msg);
    #endif
        break;
    }
    
    // ...
    
    case QL_BLE_MTU_CHANGE_EVENT:
    {
        ql_ble_mtu_change_t *mtu_change = (ql_ble_mtu_change_t *)param;
        os_printf("conn_idx: [%d], mtu_size: [%d] rn", mtu_change->conn_idx, mtu_change->mtu);
    
    #if CFG_ENABLE_QUECTEL_BLE_CENTRAL
        ql_ble_demo_msg ble_demo_msg = {0};
        ble_demo_msg.msg_id = QL_BLE_DEMO_CEN_GATT_DISV_ALL_SRV;
        ql_ble_demo_msg_send(&ble_demo_msg);
    #endif
        break;
    }
    
    // ...
    
    case QL_BLE_DEMO_CEN_GATT_DISV_ALL_SRV:
    {
        ql_ble_gattc_all_service_discovery(conn_hdl);
        break;
    }
    
  5. 发现外围设备的服务后,将生成 QL_BLE_GATT_MSG_CMP_EVT 事件,操作项为 QL_BLE_GATT_OP_PEER_SVC_DISC_END

    // ...
    case QL_BLE_GATT_MSG_CMP_EVT:
    {
        os_printf("QL_BLE_GATT_MSG_CMP_EVT, operation: [%d], status: [%d] rn",
                p_msg->param.op.operation, p_msg->param.op.status);
    
        if ((p_msg->param.op.operation == QL_BLE_GATT_OP_PEER_SVC_DISC_END) && (cen_chara_hdl != 0))
        {
    #if CFG_ENABLE_QUECTEL_BLE_CENTRAL
            ql_ble_demo_msg ble_demo_msg = {0};
            ble_demo_msg.msg_id = QL_BLE_DEMO_CEN_GATT_NTFCFG;
            ql_ble_demo_msg_send(&ble_demo_msg);
    #endif
        }
        break;
    }
    
  6. 数据成功写入外围设备后,外围设备将向中央设备发送 "123456" 数据,然后生成 QL_BLE_GATT_MSG_NTF_REQ 事件。

    // ...
    case QL_BLE_GATT_MSG_NTF_REQ:
    {
        os_printf("conn_idx: [%d], svc_id: [%d], att_idx: [%d], handle: [%d], len: [%d], data: [%s] rn",
                p_msg->conn_idx, p_msg->param.report.svc_id, p_msg->param.report.att_idx,
                p_msg->param.report.char_handle, p_msg->param.report.data.len, p_msg->param.report.data.data);
    
    #if CFG_ENABLE_QUECTEL_BLE_CENTRAL
        ql_ble_demo_msg ble_demo_msg = {0};
        ble_demo_msg.msg_id = QL_BLE_DEMO_CEN_GATT_WRREQ;
        ql_ble_demo_msg_send(&ble_demo_msg);
    #endif
        break;
    }
    

附录参考

相关文档:

文档名称
[1]: Quectel_FCM242D&FGM842D_Series_QuecOpen(SDK)_Quick_Start_Guide

术语和缩略语

术语和缩略语:

缩略语 描述
API 应用程序编程接口
BLE 低功耗蓝牙
GATT 通用属性配置文件
ID 标识符
IoT 物联网
MAC 媒体访问控制
MTU 最大传输单元
RSSI 接收信号强度指示
SDK 软件开发工具包
UUID 通用唯一标识符