本章节旨在从更高层次解释 OAD 主要概念,这些概念将在下一章节进一步扩展,某些概念例如 Boot 镜像管理( BIM )在具体实现细节上可能有所不同。但是本章尽可能的覆盖这些概念,下一章节解释它们具体实现细节。
BLE5-Stack 只支持片外 OAD(off-chip OAD)。下载的镜像文件保存在低功耗的外部 flash 里面,通过 BIM 加载到 C2640R2F 内部 flash 中。
实现 OAD 自定义 GATT service 需要两个 BLE 设备。OAD 数据交换中涉及以下定义:
名称 | 概念 |
---|---|
OAD Target | 该设备固件通过空中传输更新,该设备必须支持 TI OAD service |
OAD Downloader | 该设备负责接收镜像文件,然后通过空中传输传送给 AD Target |
OAD Target 始终是实现 OAD 服务 GATT 服务端的设备,通常是一个将要进行固件更新的 Peripheral 设备。OAT Target 使用 boot 镜像管理器( BIM )协助应用程序进行新的固件镜像文件升级。当设备复位之后执行 BIM,并确定是否进行固件更新,如果没有固件更新,BIM 将跳转到主程序运行。
OAD Downloader 始终是实现 OAD 服务 GATT 客户端的设备,通常它是提供固件更新镜像文件的 Central 设备。OAD Downloader 可以使任何满足 BLE 的设备(例如智能手机)。
图 1 显示了执行 OAD 所需的设备:
图1. OAD 环境搭建
使用 OAD 传输的所有固件均为二进制格式,它包含一个镜像文件元数据头。该元数据头的信息可用于 OAD 服务确定镜像文件是否可以下载,或用于 BIM 确定镜像文件应该被加载主程序 flash 中还是直接运行主程序。为防止该元素头信息被多次计算。所有的 TI OAD 镜像文件使用一个标准的 16 位元数据向量,该向量被嵌入到镜像文件开始处,占用应用程序固件代码的前 16 个字节。
接下来将介绍元数据向量中的各个字段及其含义。
大多数元数据检查通过 OADTarget_validateNewImage()
函数完成。
TI 提供了一个工具用于生成 OAD 就绪镜像文件,也就是包含元数据向量的将向文件,参考 Generating Metadata Vector for OAD Image。
下表显示了元数据向量各个字段的描述。
域名 | 大小(byte) | 描述 |
---|---|---|
CRC | 2 | 循环冗余校验 |
CRC Shadow | 2 | CRC影子 |
Version | 2 | 版本 |
Length | 2 | 镜像文件长度(Words) |
UID | 4 | 用户ID |
Start Address | 2 | 镜像文件目标地址(words) |
Image Type | 1 | 下载的镜像文件类型 |
State | 1 | 镜像文件状态 |
这些格式使用的是 32-bit words。举个例子,如果镜像文件长度为 0x100,实际就是 256*32/8 = 1024 byte。
OAD word 大小使用宏 EFL_OAD_ADDR_RESOLUTION
定义。
循环冗余校验(CRC)是检查镜像文件完整性的手段。
分两步进行,首先,从工具生成镜像文件时必须计算 CRC ,并存储在元数据向量中的 CRC 字段中。初始 CRC 将由OAD 服务(见 OAD 服务( 0xFFC0 )部分)通过空中发送 。
其次,一旦目标已经收到 OAD 图像,就会计算 CRC Shadow 。根据计算结果确定镜像文件在传输过程中是否已损坏,计算结果存储在元数据向量的 CRC Shadow 字段中。如果 CRC 和 CRC Shadow 相当,则目标可以假设镜像文件在空中传输时没有被破坏。
选择用于 CRC 计算的算法是 CRC-16-CCITT,它是 16 位 CRC 计算,在最坏的情况下具有 99.9984% 的错误检测率。除了该 CRC 之外,BLE 中的所有数据传输均由链路层上的 CRC 进行保护,从而进一步降低了未检测到的数据损坏风险。
镜像版本字段用于跟踪镜像的修订版本,并确保升级兼容性,客户可以实现自己的版本控制方案。 然而,TI OAD 配置文件还附加了一些检查。请参考在 oad_target_external_flash.c 中的函数 OADTarget_validateNewImage(),了解这些版本检查是如何在片外 OAD 完成的。
长度字段是镜像文件以 world 为单位的长度,其中 world 的大小由片外 OAD EFL_OAD_ADDR_RESOLUTION 定义。用户使用不同外部 flash 可能需要修改 EFL_OAD_ADDR_RESOLUTION 匹配的 world 的大小。
该字段未被 TI OAD 配置文件使用,但是客户可以添加自己的基于 UID 验证镜像文件是否正确加载。
默认情况下,片外镜像文件使用“E”,“E”,“E”,“E”。
Start Address 是镜像文件存储在内部 flash 中的第一个地址。类似于长度字段,这是用 world 计算的。片外 OAD 解决方案基于镜像文件类型对起始地址进行限制(下一节更详细地介绍)。
在具有外部 flash 的片外 OAD 系统中,可以升级多种类型的镜像文件。这些镜像文件类型包括:
Stack only
注意:虽然使用片外 OAD 可以进行 Stack 升级,但用户必须确保当前固件映像和建议的 OAD 映像之间的 App/Stack 边界 RAM 和 flash 地址没有更改。由于 App/Stack 边界上没有运行时检查,所以只有 OAD 才能覆盖应用程序。如果边界已经增长,使用此选项时,用户应该小心。TI 建议在使用片外 OAD 方法时执行应用+堆栈升级。
如果需要边界地址更改(即 Stack 正在增长或缩小),则需要用户执行合并更新( App+Stack ),以确保 OAD 映像已准备好运行。
支持的镜像类型如下所示:
镜像类型 | 值 | 描述 |
---|---|---|
EFL_OAD_IMG_TYPE_APP | 1 | 应用程序或 App+Stack 合并更新 |
EFL_OAD_IMG_TYPE_STACK | 2 | 只更新 Stack |
EFL_OAD_IMG_TYPE_NP | 3 | 网络处理器更新。这仅适用于 SimpleAP + SimpleNP 演示 |
EFL_OAD_IMG_TYPE_FACTORY | 4 | 工厂永久镜像文件,在任何 OTA 升级之前就运行在设备上 |
镜像状态是一个单字节数据字段仅用于片外 OAD 升级的方案。状态通知 BIM 该镜像是否准备好运行或已经运行,这可以防止 BIM 在每次启动时将相同的图像从外部 flash 复制到内部 flash。
OAD 服务目的是为客户提供简单的和可定制的实现。最基本的形式中,该服务负责接收/拒绝基于镜像文件头标准的 OAD 交互,将镜像存储在其适当位置。如果下载成功会重置设备,以便下载的应用程序映像由 BIM 加载到主程序区并运行。
显示 OAD 服务的 BTool 的屏幕截图如下所示:
图2. 显示 OAD 服务的 BTool
OAD 服务一个基础的服务,拥有 4 个特征值。OAD 服务的 characteristic、UUID和描述如图 2 所示。
< 注意:characteristic 使用格式为 F000XXXX-0451-4000-B000-000000000000 的 128 位 TI 基本 UUID,其中 XXXX 是缩短的 16 位 UUID。为简洁起见,本文将以 16 位的简短 UUID 表示该 characteristic。
UUID | 名字 | 描述 |
---|---|---|
0xFFC0 | OAD Service | OAD 服务声明 |
0xFFC1 | 镜像标识 | 用于发送镜像元数据,以便 OAD Target 设备可以确定是否接受或拒绝该镜像 |
0xFFC2 | 镜像块 | 镜像数据的实际块以及所占整个镜像的偏移。 |
0xFFC3 | 镜像计数 | 当前下载的完整的镜像个数 |
0xFFC4 | 镜像状态 | 当前 OAD 下载状态 |
将数据从 OAD Downloader 发送到 OAD Target 的主要方式是 GATT 写入,没有响应消息。GATT 通知用于将状态数据从 Target 发送到 Downloader 的主要方法。选择该通信方案以防止 Target 设备必须包括为了从 Downloader 接收通知所需的 GATT client 代码。该 OAD Downloader 使用寄存器 CCCD 接收任何特征的通知(通过写 01:00 到 CCCD)。
注意:GATT通知和没有响应的GATT写入都是不可靠的的消息通讯。为了确保可靠性,建议每个连接事件将OAD有效载荷传输限制为一个步骤。
镜像标识特征值用于在OAD Downloader和OAD Target之间交换镜像元数据。当OAD Downloader将OAD镜像的16字节元数据发送到Target时,OAD进程开始 。一旦接收到升级镜像的元数据,target将进行一些计算,以确定是否应该下载当前镜像。(有可能会拒绝下载,如果当前运行的镜像和要下载的镜像一样)“01:00”应写入该特性的CCCD,以便启用通知。
注意:请参阅 oad_target_external_flash.c 中 OADTarget_validateNewImage() 函数,该函数具体实现了拒绝下载镜像文件。
如果 Target 接受镜像,它将通过发送一个请求第一个镜像块的通知以继续 OAD 进程。否则 Target 将通过发送当前运行镜像的元数据的一部分来拒绝该镜像。拒绝元数据包含镜像版本和用户 ID 字段。
下图 3 是使用抓包器抓出的用于拒绝下载 OAD 镜像的数据。请注意,拒绝通知中只包含映像版本、长度和用户 ID。
图3. 抓包器抓取的拒绝下载 OAD 镜像的数据
或者图 4 所示成功启动 OAD 。
图4. 成功启动 OAD
OAD 镜像块特征用于请求和传送 OAD 图像块。“01:00” 应写入该特性的 CCCD,以便能够通知块请求。Target 发送下一个镜像块的块号的通知给 OAD Downloader,OAD Downloader 将响应( GATT 写无响应)与所述块号和一个 16 字节的 OAD 镜像块,该镜像块包含来自 OAD 镜像偏移的实际二进制数据块号。
图 5 显示了一个块请求/响应嗅探器捕获。
图5. OAD 镜像块请求/响应嗅探器捕获
OAD 图像计数特性用于设置要下载的 OAD 图像数量,这仅用于片外 OAD,特征值默认值为 1。
OAD 图像状态特性用于报告 OAD 过程中可能发生的各种故障,OAD Downloader 可以使用该信息来确定 OAD 为什么失败。它还可以纠正错误,然后再试一次。要使用这个特征的通知 “01:00” 应写入该特性的 CCCD 。
默认情况下定义了四个 OAD 状态消息,OAD 状态代码列在下表中:
OAD 状态码 | 值 | 描述 |
---|---|---|
OAD_SUCCESS | 0 | OAD 成功 |
OAD_CRC_ERR | 1 | 下载的镜像的 CRC 与元数据中预期的 CRC 不匹配 |
OAD_FLASH_ERR | 2 | 外部 flash 无法打开 |
OAD_BUFFER_OFL | 3 | 接收到的数据包的块号与请求的数据块不匹配。发生溢出。 |
客户可以根据需要扩展这些值,并使用该 OAD_sendStatus() 函数将更新发送到 OAD Downloader。
此配置文件旨在为客户提供一个简单可定制的 OAD 配置文件。在最基本的形式中,配置文件负责接受基于镜像头( header )标准的 OAD 交互,将镜像存储到 flash 上。如果下载成功会复位设备,以便下载的应用程序映像由 BIM 运行。OAD Downloader 和 OAD Target 分别执行客户端角色和服务端角色。
建立新连接后,更新连接间隔到更快的连接间隔,使能 Target 的 OAD 镜像标识和 OAD 镜像块通知。OAD Downloader 将写入镜像标识特征值到 OAD Target,消息数据升级 OAD Target 的 OAD 映像标识和 OAD 映像块特性的更快 OAD 连接间隔, OAD Downloader 将写入 OAD Target 的映像标识特性 。在接收到镜像表示特征的写入请求后,OAD Target 将可用于 OAD 升级的镜像与其自己的运行镜像进行比较。OAD Target_validateNewImage() 函数在 OAD 配置文件中负责确定新的镜像时候接受。
如果 Target 接受镜像,它将通过发送一个请求第一个镜像块的通知以继续 OA D进程。否则 Target 将通过发送当前运行镜像的元数据的一部分来拒绝该镜像。拒绝元数据包含镜像版本和用户 ID 字段。在这种情况下,OAD 过程将立即结束,如图 6 所示。
图6. OAD 过程启动和结束
镜像块传输特性值允许两个设备请求和响应 OAD 镜像,一次一个块,镜像块的大小被定义为 16 个字节。(见 oad.h 的 OAD_BLOCK_SIZE )。OAD Target 从 OAD Downloader 请求一个镜像块,通过块序号发送通知给 OAD Downloader,OAD Downloader 将通过写入 OAD 镜像块特性进行响应。
消息的数据格式是所请求的块的索引,后跟镜像的对应的 16 字节。每当 OAD Target 准备好接收OAD镜像的下一个块时,它将通过所需镜像块的索引来通知图像块传输特性值。
当 OAD Target 接收到最后一个镜像块时,对接收的所有镜像进行校验来验证这次传输是否正确的接收并存储所有镜像块。
当校验通过之后,OAD Target 将复位,以便 BIM 进行验证和加载当前接收的镜像块。最后,OAD Downloader 将失去连接,重新开始扫描,然后建立连接,连接后对新镜像进行校验,是否是新的镜像在运行。
为了确保可靠性,在 OAD 传输过程中发生的任何错误或故障都要求 OAD Downloader 重新开始启动 OAD 传输过程。如果启用通知,可能会通过 OAD 镜像状态(image state)特征值报告错误。
由于运行的映像无法更新 OAD,必须使用引导映像管理器(BIM)。BIM 是被设计为每次复位后运行,检查新下载镜像的正确性。如果正确,新的镜像将加载到内部 flash。
注意:从 BLE5-Stack 1.00.00 BIM 总是链接到内部 flash 的第 31 页,并将始终链接 CCFG 部分。因此,OAD 应用程序不需要自己的 CCFG。
一般来说,链接器命令文件必须支持 TI OAD Profile、TI Tools 和 TI BIM(TI OAD Ecosystem)的一些基本要求:
这些要求至关重要,不仅仅是在 TI OAD 系统中需要得到支持,而且在前面部分讨论过的应用程序的稳定性。
SimpleLink CC2640R2 SDK 提供 cc26xx_app_oad.cmd(CCS)和 cc26xx_app_oad.icf(IAR)链接器命令文件,以显示与 TI OAD 生态系统兼容性的这些要求。修改一个现有的连接器命令文件为一个 OAD off-chip 库文件参考: sec-generating-library-oad-linker-file。
通常,TI Image Tool 将处理 OAD 镜像的页面对齐,不需要链接器干预。但是如果需要,可以进行一些堆栈的更改,使堆栈进入点页面对齐,参见 OAD 项目的堆栈更改。
文章所有代码、工具、文档开源。加入我们QQ群 591679055获取更多支持,共同研究CC2640R2F&BLE5.0。