低功耗蓝牙库 - FreeRTOS

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

低功耗蓝牙库

重要

这是《FreeRTOS 用户指南》的存档版本,可用于 FreeRTOS 版本 202012.00。有关本文档的最新版本,请参阅《FreeRTOS 用户指南》

概览

FreeRTOS 支持通过代理设备(例如手机)使用低功耗蓝牙功能发布和订阅 MQTT 主题。借助 FreeRTOS 低功耗蓝牙库,您的微控制器可以安全地与 MQT T 代理进行通信。 AWS IoT

IoT devices connecting to mobile phone and AWS IoT Core via Bluetooth and Wi-Fi.

使用 SDKs 适用于 FreeRTOS 蓝牙设备的移动版,您可以编写本机移动应用程序,通过低功耗蓝牙与微控制器上的嵌入式应用程序进行通信。有关移动设备的更多信息 SDKs,请参阅 SDKs 适用于 FreeRTOS 蓝牙设备的移动设备

FreeRTOS 低功耗蓝牙库包含一些服务以配置 Wi-Fi 网络,传输大量数据以及通过低功耗蓝牙提供网络抽象。FreeRTOS 低功耗蓝牙库还包括中间件和 APIs 较低级别,可更直接地控制蓝牙低功耗堆栈。

架构

FreeRTOS 低功耗蓝牙库由三层组成:服务、中间件和低级别包装器。

Layered architecture diagram showing User Application at the top, followed by Services, Middleware, Low-level Wrappers, and Manufacturer BLE Stack.

服务

FreeRTOS 低功耗蓝牙服务层由四个利用 APIs中间件的通用属性 (GATT) 服务组成:设备信息、Wi-Fi 配置、网络抽象和大型对象传输。

设备信息

设备信息服务可收集有关微控制器的信息,其中包括:

  • 您的设备正在使用的 FreeRTOS 的版本。

  • 设备注册的账户的 AWS IoT 终端节点。

  • 低功耗蓝牙最大传输单元 (MTU)。

Wi-Fi 预置

利用 Wi-Fi 预置服务,具有 Wi-Fi 功能的微控制器可执行以下操作:

  • 列出范围内的网络。

  • 将网络和网络凭证保存到闪存。

  • 设置网络优先级。

  • 从闪存中删除网络和网络凭证。

网络抽象

网络抽象服务将应用程序的网络连接类型抽象化。通用 API 与您的设备的 Wi-Fi、以太网和低功耗蓝牙硬件堆栈交互,使得应用程序兼容多种连接类型。

大型对象传输

大型对象传输服务向客户端发送数据并从客户端接收数据。Wi-Fi 预置和网络抽象等其他服务使用大型对象传输服务来发送和接收数据。您还可以使用大型对象传输 API 来直接与服务交互。

中间件

FreeRTOS 低功耗蓝牙中间件是从较低级别抽象出来的。 APIs中间件 APIs为低功耗蓝牙堆栈提供了更加用户友好的界面。

使用中间件 APIs,您可以跨多个层向单个事件注册多个回调。初始化低功耗蓝牙中间件还会初始化服务并启动通告。

灵活的回调订阅

假设您的低功耗蓝牙硬件断开连接,并且低功耗蓝牙 MQTT 服务需要检测断开连接事件。您编写的应用程序可能还需要检测相同的断开连接事件。低功耗蓝牙中间件可以将事件路由到已注册回调的代码的各个部分,而不会让较高的层争用低级别资源。

低级别包装程序

低级别 FreeRTOS 低功耗蓝牙包装器是来自制造商的低功耗蓝牙堆栈的抽象。低级封装器提供了一组 APIs 用于直接控制硬件的通用封装器。低级会 APIs 优化 RAM 使用情况,但功能有限。

使用低功耗蓝牙服务 APIs 与低功耗蓝牙服务进行交互。该服务比低级 APIs服务 APIs 需要更多的资源。

依赖项和要求

低功耗蓝牙库具有以下直接依赖项:

  • 线性容器库

  • 一个平台层,直接与操作系统交互用于线程管理、计时器、时钟功能和网络访问。

Diagram showing BLE at the top connected to List/Queue, Network, and Clock components.

只有 Wi-Fi 预配置服务具有 FreeRTOS 库依赖项:

GATT 服务 依赖关系
Wi-Fi 预置 Wi-Fi 库

要与 AWS IoT MQTT 经纪人通信,您必须拥有一个 AWS 账户,并且必须将您的设备注册为 AWS IoT 事物。有关设置的更多信息,请参阅 AWS IoT 开发人员指南

在移动设备上,FreeRTOS 低功耗蓝牙使用 Amazon Cognito 进行用户身份验证。要使用 MQTT 代理服务,您必须创建一个 Amazon Cognito 身份和用户池。每个 Amazon Cognito 身份都必须附加适当的策略。有关更多信息,请参阅《Amazon Cognito 开发人员指南》。

库配置文件

使用 FreeRTOS 低功耗蓝牙 MQTT 服务的应用程序必须提供一个定义了配置参数的 iot_ble_config.h 标头文件。未定义的配置参数将采用 iot_ble_config_defaults.h 中指定的默认值。

一些重要的配置参数包括:

IOT_BLE_ADD_CUSTOM_SERVICES

允许用户创建其自己的服务。

IOT_BLE_SET_CUSTOM_ADVERTISEMENT_MSG

允许用户自定义通告和扫描响应消息。

有关更多信息,请参阅低功耗蓝牙 API 参考

优化

在优化主板性能时,请注意以下事项:

  • 低级 APIs 使用较少的 RAM,但提供的功能有限。

  • 您可以将 iot_ble_config.h 标头文件中的 bleconfigMAX_NETWORK 参数设置为一个较小的值来减少使用的堆栈量。

  • 您可以将 MTU 大小增至其最大值来限制消息缓冲,并加快代码运行速度和减少占用的 RAM。

使用限制

默认情况下,FreeRTOS 低功耗蓝牙库将 eBTpropertySecureConnectionOnly 属性设置为 TRUE,这会将设备置于“仅安全连接”模式。按照蓝牙核心规范 5.0 版第 3 册 C 部分 10.2.4 中所述,当设备处于“仅安全连接”模式中时,需要最高 LE 安全模式 1 级别(级别 4)才能访问任何权限高于最低 LE 安全模式 1 级别(级别 1)的属性。在 LE 安全模式 1 级别 4,设备必须具有输入和输出功能才能进行数字比较。

此处列出了支持的模式及其关联属性:

模式 1、级别 1(不安全)
/* Disable numeric comparison */ #define IOT_BLE_ENABLE_NUMERIC_COMPARISON ( 0 ) #define IOT_BLE_ENABLE_SECURE_CONNECTION ( 0 ) #define IOT_BLE_INPUT_OUTPUT ( eBTIONone ) #define IOT_BLE_ENCRYPTION_REQUIRED ( 0 )
模式 1、级别 2(无身份验证配对,有加密)
#define IOT_BLE_ENABLE_NUMERIC_COMPARISON ( 0 ) #define IOT_BLE_ENABLE_SECURE_CONNECTION ( 0 ) #define IOT_BLE_INPUT_OUTPUT ( eBTIONone )
模式 1、级别 3(有身份验证配对,有加密)

不支持此模式。

模式 1、级别 2(有身份验证 LE 安全连接配对,有加密)

默认支持此模式。

有关 LE 安全模式的信息,请参阅蓝牙核心规范 5.0 版第 3 册 C 部分 10.2.1。

初始化

如果您的应用程序通过中间件与低功耗蓝牙堆栈交互,则您只需初始化中间件即可。中间件负责初始化堆栈的较低层。

中间件

初始化中间件

  1. 在调用低功耗蓝牙中间件 API 之前初始化任意低功耗蓝牙硬件驱动程序。

  2. 启用低功耗蓝牙。

  3. 使用 IotBLE_Init() 初始化中间件

    注意

    如果您正在运行 AWS 演示,则不需要执行此初始化步骤。演示初始化由网络管理器处理,该管理器位于 freertos/demos/network_manager

低级 APIs

如果您不想使用FreeRTOS蓝牙低功耗GATT服务,则可以绕过中间件直接与低级交互以节省资源。 APIs

初始化低级 APIs

  1. 在调用之前,请初始化所有低功耗蓝牙硬件驱动程序 APIs。驱动程序初始化不是低功耗 APIs蓝牙低功耗的一部分。

  2. 低功耗蓝牙低级别 API 提供了对低功耗蓝牙堆栈的启用/禁用调用以优化功率和资源。在调用之前 APIs,必须启用低功耗蓝牙。

    const BTInterface_t * pxIface = BTGetBluetoothInterface(); xStatus = pxIface->pxEnable( 0 );
  3. 蓝牙管理器 APIs 包含低功耗蓝牙和经典蓝牙共有的内容。常见管理器的回调必须是第二个初始化的。

    xStatus = xBTInterface.pxBTInterface->pxBtManagerInit( &xBTManagerCb );
  4. 低功耗蓝牙适配器位于常见 API 的上方。您必须初始化其回调,就像您初始化常见 API 一样。

    xBTInterface.pxBTLeAdapterInterface = ( BTBleAdapter_t * ) xBTInterface.pxBTInterface->pxGetLeAdapter(); xStatus = xBTInterface.pxBTLeAdapterInterface->pxBleAdapterInit( &xBTBleAdapterCb );
  5. 注册新的用户应用程序。

    xBTInterface.pxBTLeAdapterInterface->pxRegisterBleApp( pxAppUuid );
  6. 初始化对 GATT 服务器的回调。

    xBTInterface.pxGattServerInterface = ( BTGattServerInterface_t * ) xBTInterface.pxBTLeAdapterInterface->ppvGetGattServerInterface(); xBTInterface.pxGattServerInterface->pxGattServerInit( &xBTGattServerCb );

    在初始化低功耗蓝牙适配器后,您可以添加 GATT 服务器。一次只能注册一个 GATT 服务器。

    xStatus = xBTInterface.pxGattServerInterface->pxRegisterServer( pxAppUuid );
  7. 设置应用程序属性,如仅安全连接和 MTU 大小。

    xStatus = xBTInterface.pxBTInterface->pxSetDeviceProperty( &pxProperty[ usIndex ] );

API 参考

有关完整 API 参考,请参阅低功耗蓝牙 API 参考

示例用法

以下示例说明了如何将低功耗蓝牙库用于通告和创建新服务。有关所有 FreeRTOS 低功耗蓝牙演示应用程序,请参阅低功耗蓝牙演示应用程序

广告

  1. 在您的应用程序中,设置通告 UUID:

    static const BTUuid_t _advUUID = { .uu.uu128 = IOT_BLE_ADVERTISING_UUID, .ucType = eBTuuidType128 };
  2. 然后,定义 IotBle_SetCustomAdvCb 回调函数:

    void IotBle_SetCustomAdvCb( IotBleAdvertisementParams_t * pAdvParams, IotBleAdvertisementParams_t * pScanParams) { memset(pAdvParams, 0, sizeof(IotBleAdvertisementParams_t)); memset(pScanParams, 0, sizeof(IotBleAdvertisementParams_t)); /* Set advertisement message */ pAdvParams->pUUID1 = &_advUUID; pAdvParams->nameType = BTGattAdvNameNone; /* This is the scan response, set it back to true. */ pScanParams->setScanRsp = true; pScanParams->nameType = BTGattAdvNameComplete; }

    此回调在通告消息中发送 UUID,在扫描响应中发送全名。

  3. 打开 vendors/vendor/boards/board/aws_demos/config_files/iot_ble_config.h 并将 IOT_BLE_SET_CUSTOM_ADVERTISEMENT_MSG 设置为 1。这将触发 IotBle_SetCustomAdvCb 回调。

添加新服务

有关服务的完整示例,请参阅 freertos/.../ble/services

  1. UUIDs 为服务的特征和描述符创建:

    #define xServiceUUID_TYPE \ {\ .uu.uu128 = gattDemoSVC_UUID, \ .ucType = eBTuuidType128 \ } #define xCharCounterUUID_TYPE \ {\ .uu.uu128 = gattDemoCHAR_COUNTER_UUID,\ .ucType = eBTuuidType128\ } #define xCharControlUUID_TYPE \ {\ .uu.uu128 = gattDemoCHAR_CONTROL_UUID,\ .ucType = eBTuuidType128\ } #define xClientCharCfgUUID_TYPE \ {\ .uu.uu16 = gattDemoCLIENT_CHAR_CFG_UUID,\ .ucType = eBTuuidType16\ }
  2. 创建缓冲区以注册特性和描述符的处理:

    static uint16_t usHandlesBuffer[egattDemoNbAttributes];
  3. 创建属性表。为节省一些 RAM,请将表定义为 const

    重要

    始终按顺序创建属性,将服务作为第一个属性。

    static const BTAttribute_t pxAttributeTable[] = { { .xServiceUUID = xServiceUUID_TYPE }, { .xAttributeType = eBTDbCharacteristic, .xCharacteristic = { .xUuid = xCharCounterUUID_TYPE, .xPermissions = ( IOT_BLE_CHAR_READ_PERM ), .xProperties = ( eBTPropRead | eBTPropNotify ) } }, { .xAttributeType = eBTDbDescriptor, .xCharacteristicDescr = { .xUuid = xClientCharCfgUUID_TYPE, .xPermissions = ( IOT_BLE_CHAR_READ_PERM | IOT_BLE_CHAR_WRITE_PERM ) } }, { .xAttributeType = eBTDbCharacteristic, .xCharacteristic = { .xUuid = xCharControlUUID_TYPE, .xPermissions = ( IOT_BLE_CHAR_READ_PERM | IOT_BLE_CHAR_WRITE_PERM ), .xProperties = ( eBTPropRead | eBTPropWrite ) } } };
  4. 创建回调阵列。此回调阵列必须与以上定义的表阵列采用相同的顺序。

    例如,如果在访问 xCharCounterUUID_TYPE 时触发 vReadCounter,并在访问 xCharControlUUID_TYPE 时触发 vWriteCommand,则定义阵列如下:

    static const IotBleAttributeEventCallback_t pxCallBackArray[egattDemoNbAttributes] = { NULL, vReadCounter, vEnableNotification, vWriteCommand };
  5. 创建服务:

    static const BTService_t xGattDemoService = { .xNumberOfAttributes = egattDemoNbAttributes, .ucInstId = 0, .xType = eBTServiceTypePrimary, .pusHandlesBuffer = usHandlesBuffer, .pxBLEAttributes = (BTAttribute_t *)pxAttributeTable };
  6. 使用您在上一步中创建的结构调用 API IotBle_CreateService。中间件同步所有服务的创建,因此在触发 IotBle_AddCustomServicesCb 回调时必须已经定义好了所有新服务。

    1. vendors/vendor/boards/board/aws_demos/config_files/iot_ble_config.h 中将 IOT_BLE_ADD_CUSTOM_SERVICES 设置为 1

    2. AddCustomServicesCb 在您的应用程序中创建 IotBle _:

      void IotBle_AddCustomServicesCb(void) { BTStatus_t xStatus; /* Select the handle buffer. */ xStatus = IotBle_CreateService( (BTService_t *)&xGattDemoService, (IotBleAttributeEventCallback_t *)pxCallBackArray ); }

移植

用户输入和输出外围设备

安全连接需要输入和输出以进行数字比较。可使用事件管理器注册 eBLENumericComparisonCallback 事件:

xEventCb.pxNumericComparisonCb = &prvNumericComparisonCb; xStatus = BLE_RegisterEventCb( eBLENumericComparisonCallback, xEventCb );

外围设备必须显示数字密钥,并将比较结果作为输入。

移植 API 实施

要将 FreeRTOS 移植到新目标,必须为 Wi-Fi 配置服务和蓝牙低功耗功能实现 APIs 一些功能。

低功耗蓝牙 APIs

要使用 FreeRTOS 低功耗蓝牙中间件,必须实现一些。 APIs

APIs 常见于蓝牙经典版的 GAP 和低功耗蓝牙的 GAP 之间
  • pxBtManagerInit

  • pxEnable

  • pxDisable

  • pxGetDeviceProperty

  • pxSetDeviceProperty(所有选项都是强制性的,eBTpropertyRemoteRssieBTpropertyRemoteVersionInfo 除外)

  • pxPair

  • pxRemoveBond

  • pxGetConnectionState

  • pxPinReply

  • pxSspReply

  • pxGetTxpower

  • pxGetLeAdapter

  • pxDeviceStateChangedCb

  • pxAdapterPropertiesCb

  • pxSspRequestCb

  • pxPairingStateChangedCb

  • pxTxPowerCb

APIs 专门针对低功耗蓝牙的 GAP
  • pxRegisterBleApp

  • pxUnregisterBleApp

  • pxBleAdapterInit

  • pxStartAdv

  • pxStopAdv

  • pxSetAdvData

  • pxConnParameterUpdateRequest

  • pxRegisterBleAdapterCb

  • pxAdvStartCb

  • pxSetAdvDataCb

  • pxConnParameterUpdateRequestCb

  • pxCongestionCb

GATT 服务器
  • pxRegisterServer

  • pxUnregisterServer

  • pxGattServerInit

  • pxAddService

  • pxAddIncludedService

  • pxAddCharacteristic

  • pxSetVal

  • pxAddDescriptor

  • pxStartService

  • pxStopService

  • pxDeleteService

  • pxSendIndication

  • pxSendResponse

  • pxMtuChangedCb

  • pxCongestionCb

  • pxIndicationSentCb

  • pxRequestExecWriteCb

  • pxRequestWriteCb

  • pxRequestReadCb

  • pxServiceDeletedCb

  • pxServiceStoppedCb

  • pxServiceStartedCb

  • pxDescriptorAddedCb

  • pxSetValCallbackCb

  • pxCharacteristicAddedCb

  • pxIncludedServiceAddedCb

  • pxServiceAddedCb

  • pxConnectionCb

  • pxUnregisterServerCb

  • pxRegisterServerCb

有关将 FreeRTOS 低功耗蓝牙库移植到您的平台的更多信息,请参阅《FreeRTOS 移植指南》中的移植低功耗蓝牙库