本文参考UM-B-119_DA14585-DA14531_SW_Platform_Reference做的学习笔记,由于本人水平有限,文中难免有遗漏或错误之处,还请谅解和指正。
环境描述
名称 | 环境描述 |
---|---|
操作系统 | Windows10专业工作站版 ,版本号1909 |
SoC | DA14531 |
SDK | 6.0.12.1020.2 |
Keil | μVision V5.15 |
参考文件 | UM-B-119_DA14585-DA14531_SW_Platform_Reference |
低功耗蓝牙
DA14531执行的是标准的蓝牙5.1。只支持单模式BLE,不支持基本速率(BR)和增强数据速率协议(EDR)。
- L2CAP和SMP不直接从应用程序层访问
- ATT层的功能是由GATT提供的,具体数据库API可用于实现与配置文件相关的功能
- 大多数的操作都是在GAP和GATT层,在SDK中提供了现成的实现库文件:prf_utils.c
- 图中箭头所指的地方就是用户可以使用的API,详见下表。
API | API Files | 作用 | 文件位置 |
---|---|---|---|
ATT Database (ATTDB) | attm_db.h | 属性协议数据库,存放属性配置文件服务不同的属性值,用户可以根据需求进行更改 | sdk\ble_stack\host\att\attm |
GAP Manager | gapm.h | 通用访问配置文件管理器。为应用程序提供API,管理所有未连接的内容,例如将设备配置为进入所需模式(可发现,可连接等)并执行所需的操作(扫描,连接等)GAP管理器还负责根据相应的BLE连接状态管理GAP控制器状态。 | sdk\ble_stack\host\gap\gapm |
gapm_task.h | 处理往返于GAP Manager块的所有消息。它处理来自与正在进行的连接无关的较低层和较高层的消息。 | ||
gapm_util.h | 通用访问配置文件管理器工具箱,比如设置广播数据 | ||
GAP Controller | gapc.h | 通用访问配置文件控制器。负责向应用程序提供API,以执行与BLE连接相关的GAP操作(配对,更新参数,断开连接). GAP控制器是多实例化的,每个BLE连接一个任务实例。 | sdk\ble_stack\host\gap\gapc |
gapc_task.h | 处理往返于GAP控制器块的所有消息,它处理来自与正在进行的连接有关的上,下层的消息 | ||
GATT Manager | gattm.h | 通用属性配置文件。GATT管理器模块负责为与连接无关的所有操作提供API。 它负责管理内部数据库。 | sdk\ble_stack\host\gap\gatt |
gattm_task.h | 处理与连接无关的所有GATT块操作。GATTMTASK负责管理内部属性数据库和GATT控制器的状态,它们管理与连接有关的GATT块操作。消息可能源自@ref ATTM“ ATTM”,@ ref GAP“ GAP”和应用程序。 | ||
GATT Controller | gattc.h | 通用属性配置文件控制器。 该GATT模块负责为与BLE连接有关的所有属性相关操作提供API。它负责所有使用属性协议发现服务和用于读取和对端设备的写入特征值服务框架的活动。为此,GATT与@ref ATTC“ ATTC”和@ref ATTS“ ATTS”连接。 | sdk\ble_stack\host\gap\gattc |
gattc_task.h | 处理往返于GATT控制器模块的所有消息。GATTCTASK负责管理来自属性层和主机层的消息以进行专用连接。该任务包括服务和特征发现,配置交换以及属性值访问操作(读取,写入,通知和指示)。消息可能源自@ref ATTC“ ATTC”,@ ref ATTS“ ATTS”,@ ref GAP“ GAP”和应用程序。 | ||
Profile Utilities | prf_utils.h | 一些关于profile服务属性、服务特征的工具函数,如在对等设备上请求服务特征发现 | sdk\ble_stack\host\profiles |
prf_utils_128.h | 一些关于profiles服务与UUID相关的一些工具函数,比如检查服务特征的有效性,根据UUID查找相关的特征等 | ||
prf_types.h | 一些与profiles相关的结构体 | ||
'profiles‘ | ''profile'.h | profiles的头文件 | \sdk\ble_stack\profiles |
''profile_task'.h | profiles的任务配置头文件 | ||
Custom Profile | custs1_task.h | 自定义profiles的任务配置头文件 | sdk\ble_stack\profiles\custom\custs,每一个头文件都对应着一个.c文件 |
custs1.h | 自定义profiles的头文件 |
GAP层
RW-BLE GAP定义了与蓝牙设备的发现和链接管理有关的基本过程,为LE GAP(参考文章)提供了完整且实质的支持.
- 四个角色:中央设备、外围设备、广播、扫描
- 广播和扫描
- 模式:发现、连接、绑定
- 安全与认证,加密和签名
- 连接的建立与断开
- 随机和静态地址
- 隐私功能
- 配对和密钥生成
RW-BLE GAP由两个部分组成:
- GAP管理器(GAPM)
- 管理与已建立的链接无关的所有应用程序请求
- GAP控制器(GAPC)
- 在与对等设备的连接上创建的,并在连接终止时被删除
GAP管理器初始化在system_init() 函数中进行。当GAP实体已初始化并准备向上层提供服务时,GAP实体将调度该 GAPM_DEVICE_READY_IND消息。该消息在GAP应用程序模块内部处理。作为响应,GAP模块将GAP管理器配置为特定角色,以GAPM_SET_DEV_CONFIG消息。GAP Manager配置完成后,设备已准备好初始化数据库,然后根据所选角色进行扫描和播发之类的操作,以与其他对等方建立连接。
例如:开始广告,将GAPM_START_ADVERTISE_CMD的消息编译并发送到GAPM,然后由KE_MSG_ALLOC分配内存空间。代码如下:
代码路径:/SDK/app_modules/api/api_mid.h
/**
****************************************************************************************
* @brief Create a start advertise message.
* @return The pointer to the created message.
****************************************************************************************
*/
__STATIC_FORCEINLINE struct gapm_start_advertise_cmd* app_advertise_start_msg_create(void)
{
struct gapm_start_advertise_cmd* cmd = KE_MSG_ALLOC(GAPM_START_ADVERTISE_CMD,
TASK_GAPM,
TASK_APP,
gapm_start_advertise_cmd);
return cmd;
}
通过代码可以看出,这是一个内联的结构体函数,名称为app_advertise_start_msg_create,其主要作用是,创建一个开始广播的消息,这把创建消息的结构体封装成了一个带返回值的结构体函数,方便后续赋值的时候调用。在函数内部可以看到是使用了KE_MSG_ALLOC这个函数来分配内存空间,其主要参数和说明见下表:
参数 | 说明 |
---|---|
GAPM_START_ADVERTISE_CMD | 消息标识符,在gapm_msg_di中已经枚举出来 |
TASK_GAPM | 目标任务标识符,该任务的目的地* |
TASK_APP | 源任务标识符,该任务的起点* |
gapm_start_advertise_cmd | 参数结构体,结构体定义在gapm_start_advertise_cmd* |
这里KE_MSG_ALLOC是把RW内核中的ke_msg_alloc函数进行了封装,代码如下
void *ke_msg_alloc(ke_msg_id_t const id,
ke_task_id_t const dest_id,
ke_task_id_t const src_id,
uint16_t const param_len)
KE_MSG_ALLOC的代码如下:
#define KE_MSG_ALLOC(id, dest, src, param_str) \
(struct param_str*) ke_msg_alloc(id, dest, src, sizeof(struct param_str))
最后一个参数是用sizeof来计算结构体的长度。
写入结构体的参数的数据,代码如下:
代码路径:/SDK/app_modules/api/api_mid.h
struct gapm_start_advertise_cmd* cmd;
cmd = app_advertise_start_msg_create();
cmd->op.code = GAPM_ADV_NON_CONN; //启动不可连接的广播
cmd->op.addr_src = address_src_type;
cmd->intv_max = interval;
cmd->intv_min = interval;
cmd->channel_map = channel_map;
cmd->info.host.mode = advertise_mode;
cmd->info.host.adv_filt_policy = adv_filt_policy;
cmd->info.host.adv_data_len = advertise_data_len;
可以看出结构体gapm_start_advertise_cmd有许多成员,
/// Set advertising mode Command
struct gapm_start_advertise_cmd
{
/// GAPM requested operation:
/// - GAPM_ADV_NON_CONN: Start non connectable advertising 启动不可连接的广播
/// - GAPM_ADV_UNDIRECT: Start undirected connectable advertising 启动无定向可连接的广播
/// - GAPM_ADV_DIRECT: Start directed connectable advertising启动定向连接广播
/// - GAPM_ADV_DIRECT_LDC: Start directed connectable advertising using Low Duty Cycle 使用地占空比的定向连接广播
struct gapm_air_operation op;
/// Minimum interval for advertising 广播最小时间间隔
uint16_t intv_min;
/// Maximum interval for advertising 广播最大时间间隔
uint16_t intv_max;
///Advertising channel map 广播通道map
uint8_t channel_map;
/// Advertising information 广播的信息
union gapm_adv_info
{
/// Host information advertising data (GAPM_ADV_NON_CONN and GAPM_ADV_UNDIRECT) 主机信息广播数据
struct gapm_adv_host host;
/// Direct address information (GAPM_ADV_DIRECT) 直接地址信息
/// (used only if reconnection address isn't set or host privacy is disabled) 仅在未设置重连接地址或禁用主机隐私时使用
struct gap_bdaddr direct;
} info;
};
在这个结构体内部,还包含了其他的结构体信息,
/// Air operation default parameters 空中默认参数
struct gapm_air_operation
{
/// Operation code.操作码
uint8_t code;
/**
* Own BD address source of the device: 设备自身的BD地址源:
* - GAPM_STATIC_ADDR: Public or Random Static Address according to device address configuration
* - GAPM_GEN_RSLV_ADDR: Generated Random Resolvable Private Address
* - GAPM_GEN_NON_RSLV_ADDR: Generated Random non-Resolvable Private Address
*/
uint8_t addr_src;
/// Dummy data use to retrieve internal operation state (should be set to 0).
//虚拟数据用于检索内部操作状态(应设置为0)。
uint16_t state;
};
上述结构体用于设置广播时候的状态和设备自身的地址
/// Advertising data that contains information set by host.包含由主机设置的信息的广告数据。
struct gapm_adv_host
{
/// Advertising mode : 广播模式
/// - GAP_NON_DISCOVERABLE: Non discoverable mode 不可发现模式
/// - GAP_GEN_DISCOVERABLE: General discoverable mode 常规可发现模式
/// - GAP_LIM_DISCOVERABLE: Limited discoverable mode 受限的可发现模式
/// - GAP_BROADCASTER_MODE: Broadcaster mode 广播模式
uint8_t mode;
/// Advertising filter policy:
/// - ADV_ALLOW_SCAN_ANY_CON_ANY: Allow both scan and connection requests from anyone
/// - ADV_ALLOW_SCAN_WLST_CON_ANY: Allow both scan req from White List devices only and
/// connection req from anyone
/// - ADV_ALLOW_SCAN_ANY_CON_WLST: Allow both scan req from anyone and connection req
/// from White List devices only
/// - ADV_ALLOW_SCAN_WLST_CON_WLST: Allow scan and connection requests from White List
/// devices only
uint8_t adv_filt_policy;
/// Advertising data length - maximum 28 bytes, 3 bytes are reserved to set
/// Advertising AD type flags, shall not be set in advertising data
uint8_t adv_data_len;
/// Advertising data
uint8_t adv_data[ADV_DATA_LEN];
/// Scan response data length- maximum 31 bytes
uint8_t scan_rsp_data_len;
/// Scan response data
uint8_t scan_rsp_data[SCAN_RSP_DATA_LEN];
/// Peer Info - bdaddr
struct gap_bdaddr peer_info;
};
上述结构体包含了由主机设置相关信息的广播数据。
当远程对等方尝试连接到设备时,GAP控制器将通过GAPC_CONNECTION_REQ_IND向应用程序报告对等方的请求。 由于堆栈现在是指特定的连接,因此消息现在将从相关的GAP控制器传递到相关的GAP控制器。 应用程序GAP处理程序将以所需的安全要求响应此请求,并将尝试根据要求与对等方建立安全或非安全连接。 安全管理协议消息通过GAP控制器到达应用程序。 建立安全连接后,设备将连接并且可以开始使用可用的配置文件服务。 每个服务可能都有其自己的安全性要求,建立具有足够安全性的连接会将服务暴露给对等方。
在app_task.c中,可以看到以下代码,
static const struct ke_msg_handler app_gap_process_handlers[]=
{
{GAPM_DEVICE_READY_IND, (ke_msg_func_t)gapm_device_ready_ind_handler},
{GAPM_CMP_EVT, (ke_msg_func_t)gapm_cmp_evt_handler},
{GAPC_CMP_EVT, (ke_msg_func_t)gapc_cmp_evt_handler},
{GAPC_CONNECTION_REQ_IND, (ke_msg_func_t)gapc_connection_req_ind_handler},
{GAPC_DISCONNECT_IND, (ke_msg_func_t)gapc_disconnect_ind_handler},
{GAPC_GET_DEV_INFO_REQ_IND, (ke_msg_func_t)gapc_get_dev_info_req_ind_handler},
{GAPC_SET_DEV_INFO_REQ_IND, (ke_msg_func_t)gapc_set_dev_info_req_ind_handler},
{GAPM_PROFILE_ADDED_IND, (ke_msg_func_t)gapm_profile_added_ind_handler},
{GAPM_ADV_REPORT_IND, (ke_msg_func_t)gapm_adv_report_ind_handler},
{GAPC_PARAM_UPDATE_REQ_IND, (ke_msg_func_t)gapc_param_update_req_ind_handler},
{GAPC_LE_PKT_SIZE_IND, (ke_msg_func_t)gapc_le_pkt_size_ind_handler},
{GATTC_SVC_CHANGED_CFG_IND, (ke_msg_func_t)gattc_svc_changed_cfg_ind_handler},
{GAPC_PEER_FEATURES_IND, (ke_msg_func_t)gapc_peer_features_ind_handler},
#if (BLE_APP_SEC)
{GAPC_SECURITY_IND, (ke_msg_func_t)gapc_security_ind_handler},
#endif
};
可以看出GAPC_CONNECTION_REQ_IND所对应的函数是gapc_connection_req_ind_handler,这就是处理来自GAP的连接完成事件。
BLE数据服务
与对等设备建立连接后,与GAP相关的操作仅管理连接的某些方面,例如更改连接参数,安全级别或删除连接。BLE连接的数据服务通过数据库提供。BLE堆栈为应用程序提供了许多API,以管理和与本地和远程数据库交换数据。这些是GATT Manager API和GATT Controller API。另外,程序员也可以直接使用属性数据库API(ATTDB),而不必通过GATT在数据库中添加和管理服务和特性。其背后的原因是产生更小而有效的代码。用户可以通过GATT使用任何一种方法,也可以直接使用ATTDB。
服务名 | 内容 | 作用 |
---|---|---|
GATT | GATT 管理器 | 1、与特定的连接无关,仅实例化一次,就能提供用于管理内部属性数据库的消息AP; 2、位于配置文件或应用程序与ATT管理器之间,并在他们之间传递消息,提供服务和属性操作,例如向数据库添加服务和特征,设置和获取权限级别以及设置和获取属性值。 |
GATT控制器 | 1、与特定的BLE连接实例有关。客户端和服务器都使用该接口; 2、在客户端中,该接口用于发现、读取和写入对等设备的属性,并接收通知或指示; 3、在服务器端,当对等设备请求修改数据库时,将通知此接口,并发送指示或通知。 | |
ATTDB | ATTDB API | 1、不需要使用GAPP管理器API,用户可以直接使用本机属性数据库API; 2、将元素(服务和属性)添加到数据库,选择元素在数据库中的位置,隐藏/显示属性以及管理权限及其值,对于的ATTDB支持的功能的详细说明,请参阅文件attm_db.h,attm_db_128.h和 attm_util.h。 |
BLE Profiles
在SDK中列举了很多的Profiles,文件路径为**\sdk\ble_stack\profiles**,在每一个Profile中都包含了两种角色(服务器端和客户端)的 .h 文件和 .c文件,服务器端在本地设备上公开配置文件数据库。客户端读取,写入和管理远程设备的数据库。
根据配置文件,配置文件特定部分可以包括在有或没有通知的情况下更新特定属性,以及处理和验证来自对等设备的写入尝试。
类似的原则也适用于客户端配置文件。客户端将包括对预期服务的描述,函数和消息处理程序的初始化,启用客户端,保存发现结果以及处理程序的错误和断开连接。根据特定的配置文件,可能存在用于读取和写入操作的特殊处理程序,以及与特定属性相关的通知接收。有关详细信息,请参阅支持站点中每个配置文件的可用文档,或浏览 profile.h和profile_task.h头文件。
该SDK提供了一组有用的辅助函数,以访问GATT和ATTDB服务。它们位于中,prf_utils.h并且在现有配置文件代码中经常使用。有关详细信息,请参阅prf_utils.h
LE数据包长度拓展
对于Bluetooth Core版本4.0和4.1,最大数据包数据单元(PDU)大小为27个八位位组。蓝牙核心版本4.2引入了一项重要的增强功能,即LE数据包长度扩展,该功能允许PDU的大小在27到251个八位位组之间。这意味着,例如,与以前的Bluetooth Core版本的21个八位字节相比,L2CAP层现在可以在每个L2CAP PDU中填充多达245个八位字节的高层数据包。这种增加是10倍以上。因此,每个数据包发送的有用用户数据量的增加使设备传输数据的速度比以前的版本快2.5倍。这对于可能需要传输大量数据的应用程序将是非常有益的。例如,空中(OTA)固件更新或从传感器下载大数据日志。
为了在建立的连接上扩展默认PDU大小,必须执行数据长度更新过程。根据此控制过程,所连接的设备必须交换LL_LENGTH_REQ和LL_LENGTH_RSP PDU,以便将对等设备的功能通知每个PDU。每个设备使用这些PDU报告其最大接收数据通道和最大发送数据通道PDU有效负载长度和PDU时间。在此更新过程之后,两个控制器将连接数据路径每个方向的PDU大小都设置为交换的最小值。
DA14585 / 586/531支持LE数据长度扩展功能。应根据最大允许大小来计算最大传输单位(MTU)。这意味着,如果在连接期间数据包长度发生变化,则在计算MTU时应考虑最大数据包长度。对于演示DLE功能的SUOTA示例,最大有效载荷的长度为251个八位位组,而L2CAP标头的长度为4个八位位组。这意味着MTU大小将为251-4 = 247个八位位组。
注意:并非所有的主设备都可以使用DLE,因为它必须是Bluetooth Core 4.2版。请检查主设备中安装的版本。如果主设备不支持DLE,则根据蓝牙核心版本使用默认的MTU大小。