固件升级

更新时间:2023-01-29 07:32:16下载pdf

涂鸦 IoT 开发平台提供 固件 OTA 升级 功能,以满足客户在产品发布后,仍可对已出货设备进行固件版本升级的需求。本节课将介绍不同开发方式下固件 OTA 升级的方法、涂鸦方案的 OTA 流程与交互协议、以及如何在 涂鸦蓝牙 SDK 的基础上移植 OTA 功能。

OTA 方案

模组 OTA

涂鸦标准模组

如果您使用的是 涂鸦标准蓝牙模组,那么其配套的 涂鸦蓝牙模组 SDK 已经封装了 OTA 的实现,即模组已经具备了固件 OTA 升级的能力。您可以直接在 涂鸦 IoT 开发平台 上传固件来完成 OTA 升级任务。具体步骤,请参考下文的 操作步骤

自研模组

如果您使用的是 自研模组,则需要先完成 OTA 功能与芯片平台的适配,您可以使用 涂鸦蓝牙 SDK 提供的接口来实现固件 OTA 升级功能,再通过 涂鸦 IoT 开发平台 来创建 OTA 升级任务。

后文将为您介绍涂鸦方案的 OTA 流程、交互协议,以及涂鸦蓝牙 SDK 中有关 OTA 升级的接口。您可以根据这些信息来实现 OTA 升级程序。

MCU OTA

涂鸦蓝牙 SDK 中已实现了对蓝牙协议模组之外的 MCU 进行 OTA 升级的处理程序,其主要通过串口通信方式与 MCU 进行 OTA 升级文件等相关信息的交互。该方案适用于除了基于涂鸦蓝牙 SDK 开发的涂鸦模组或自研模组外,还包含额外 MCU 的产品。

在涂鸦 IoT 开发平台上新增 MCU 固件时,固件类型要选择 MCU 固件,涂鸦蓝牙 SDK 接收到 OTA 升级请求时才会将该固件传输给 MCU 进行升级。

另外,您需要根据 蓝牙通用串口协议 中的 MCU OTA 相关接口介绍,实现 MCU 侧的串口通信程序和 OTA 数据处理程序,从而实现 MCU OTA 完整链路。您也可以在涂鸦 IoT 开发平台上进入该产品的 硬件开发 页面,将 云端接入方式 临时切换到 MCU SDK,以便能在开发资料中下载 MCU SDK。MCU SDK 已经基于涂鸦蓝牙通用串口协议和 OTA 升级协议,实现了串口数据通信与 OTA 升级的程序框架。您只需在此基础上完成 UART 和 Flash 读写等功能与 MCU 平台的适配,即可快速实现 MCU 侧的 OTA 能力接入。具体信息,请参考 MCU SDK 移植

如果您不想使用串口方式进行 OTA 数据传输,可以参考本章的 MCU OTA 移植 完成通信程序的移植。

OTA 流程

升级流程

固件升级

操作步骤

新增固件版本

  1. 要升级固件,首先必须将新版本固件上传至 涂鸦 IoT 开发平台。在上传固件之前,先确认固件是否已经升级了版本号,即在 tuya_ble_sdk_demo.h 文件中修改 TY_DEVICE_FVER_NUMTY_DEVICE_FVER_STR 的值。本课程中直接以升级为 0.2 版本为例:

    /* 修改固件版本号,上传固件时填写的版本号需与这里一致 */
    #define TY_DEVICE_FIR_NAME    "ble_module_sdk_development_demo"
    #define TY_DEVICE_FVER_NUM    0x00000002
    #define TY_DEVICE_FVER_STR    "0.2"
    

    蓝牙单点固件的版本号一般采用 bv.sv (0.0-99.99) 格式。实际应用场景中,正式发布的版本一般为 1.0 及以上版本,可参考下表修改,然后编译代码生成新的固件,我们称之为 升级固件

    版本升级 TY_DEVICE_FVER_NUM TY_DEVICE_FVER_STR
    1.0 > 1.1 0x00000100 > 0x00000101 "1.0" > "1.1"
    2.10 > 3.0 0x0000020A > 0x00000300 "2.10" > "3.0"
  2. 接下来,进入 涂鸦 IoT 开发平台固件管理 页面,找到对应的固件,单击 新建版本

    固件升级

  3. 新增固件版本 页面填入和固件中一致的 固件版本号 并上传该固件,填写好其他内容后单击 保存并上架

    固件升级

  4. 在设置好固件上架范围后单击 确认上架,即可看到下图页面。该页面也可通过 固件管理 页面操作栏中的 详情进入,可以看到该页面也有 新增固件版本 页面的入口。

    固件升级

新建升级任务

  1. 从左侧导航栏 产品 > 设备 > 固件 OTA 可进入 固件升级 页面。

  2. 切换到要升级的产品后,选择好对应的固件,然后单击 新增固件升级 来新建升级任务。

    固件升级

  3. 参考下图,在 新增固件升级 页面填写升级信息后,单击 确定。此处以 App 提醒升级 为例。

    固件升级

  4. 在正式发布升级任务之前,可以通过测试设备来验证升级任务,单击下图中的 验证 进入设备验证页面。

    固件升级

添加设备验证

  1. 单击 通过设备号直接添加,填入测试设备的 设备虚拟 ID

    固件升级

    设备虚拟 ID 可在测试设备的设备面板中找到,操作方法如下图所示。

    固件升级

  2. 添加完成后,打开 智能生活 App 进入该产品的设备面板时,即可看到升级提醒弹出,按照提示完成升级。

    固件升级

  3. 回到 涂鸦 IoT 开发平台,单击 验证是否完成升级,测试结果显示 验证成功

    固件升级

发布升级任务

最后,单击 发布 进入 版本发布 页面,并根据实际需要选择灰度发布或全量发布后提交。

固件升级

OTA 协议

本节将介绍固件 OTA 升级过程中智能生活 App 与涂鸦蓝牙模组之间的通信协议。如果您正在使用 涂鸦蓝牙模组 SDK,可通过本节表格中的标识符找到代码中对应的宏和变量。

数据格式

帧格式

字段 字节数 说明
type 1 OTA 指令类型,由 tuya_ble_ota_data_type_t 定义
data_len 2 OTA 数据长度,即 p_data 所占字节数
p_data data_len OTA 数据,具体请参考下文的 交互协议

OTA 指令

tuya_ble_ota_data_type_t 定义的 OTA 指令如下:

OTA 指令 标识符 指令值
OTA 升级请求 TUYA_BLE_OTA_REQ 0x00
OTA 升级文件信息 TUYA_BLE_OTA_FILE_INFO 0x01
OTA 升级文件偏移量 TUYA_BLE_OTA_FILE_OFFSET_REQ 0x02
OTA 升级数据 TUYA_BLE_OTA_DATA 0x03
OTA 升级结束 TUYA_BLE_OTA_END 0x04

交互协议

OTA 升级请求

App -> 设备

p_data 字节数 标识符 说明
[0] 1 type 固定为 0。

设备 -> App

p_data 字节数 标识符 说明
[0] 1 flag 升级请求响应标志。
  • 00:允许升级
  • 01:拒绝升级
[1] 1 ota_version OTA 协议大版本。例如 03 代表 3.x 版本的 OTA 协议。
[2] 1 type 固定为 0。
[3:6] 4 version 当前固件版本号。大端格式,例如 00 00 02 0A 代表 V2.10。
[7:8] 2 package_maxlen 设备允许的单包数据最大长度。当前版本协议中设定的最大长度是 512 字节。

OTA 升级文件信息

App -> 设备

p_data 字节数 标识符 说明
[0] 1 type 固定为 0。
[1:8] 8 pid 产品 PID。保留字段。产品支持 OEM 时会存在 PID 不一致的情况。建议设备在 OTA 时无需校验 PID 并忽略该参数。
[9:12] 4 version 升级文件版本号。大端格式,例如 00 00 03 00 代表 V3.0。
[13:28] 16 md5 升级文件 MD5。
[29:32] 4 file_len 升级文件长度。
[33:36] 4 crc32 CRC32。

设备 -> App

p_data 字节数 标识符 说明
[0] 1 type 固定为 0。
[1] 1 state 升级状态。
  • 00:正常升级。
  • 01:产品 PID 不一致。
  • 02:升级文件版本低于或等于当前固件版本。
  • 03:升级文件大小超过范围。
[2:5] 4 old_file_len 已储存文件长度,用于断点续传。App 会根据已储存文件长度计算新文件的 CRC32。
[6:9] 4 old_crc32 已储存文件 CRC32,用于断点续传。App 会将已储存文件的 CRC32 与计算出的新文件的 CRC32 进行比较。
[10:25] 16 old_md5 已储存文件 MD5。目前不使用。

OTA 升级文件偏移量

App -> 设备

p_data 字节数 标识符 说明
[0] 1 type 固定为 0。
[1:4] 4 offset 升级文件偏移量。

设备 -> App

p_data 字节数 标识符 说明
[0] 1 type 固定为 0。
[1:4] 4 offset 设备要求的起始传输文件偏移量。实际文件传输的偏移地址应该以设备端要求的为准。设备端要求的地址会小于等于 App 端给出的偏移。

OTA 升级文件数据

App -> 设备

p_data 字节数 标识符 说明
[0] 1 type 固定为 0。
[1:2] 2 pkg_id 升级文件数据包号。从 0 开始,高字节在前。
[3:4] 2 len 当前包数据长度 n
[5:6] 2 crc16 当前包数据 CRC16。
[7:(7+n-1)] n data 当前包数据。

设备 -> App

p_data 字节数 标识符 说明
[0] 1 type 固定为 0。
[1] 1 state 升级状态。
  • 00:正常升级。
  • 01:包号异常。
  • 02:长度不一致。
  • 03:CRC 校验失败。
  • 04:其他异常。

OTA 升级结束

App -> 设备

p_data 字节数 标识符 说明
[0] 1 type 固定为 0。

设备 -> App

p_data 字节数 标识符 说明
[0] 1 type 固定为 0。
[1] 1 state 升级状态。
  • 00:升级成功。
  • 01:数据总长度错误。
  • 02:数据总 CRC 校验失败。
  • 03:其他异常。

OTA 实现

模组 OTA 移植

如果您使用自研模组进行开发,则需要在 涂鸦蓝牙 SDK 基础上,根据前文介绍的 OTA 协议完成模组 OTA 功能的开发。您可以在 涂鸦 IoT 开发平台 上下载任意的 涂鸦蓝牙模组 SDK 作为参考,或参考下文内容完成 OTA 程序移植。

入口函数

初始化

在 SDK 初始化之后添加 OTA 初始化函数。

void tuya_ble_sdk_demo_init(void)
{
	/* ... */
	tuya_ble_sdk_init(&tuya_ble_device_param);              /* SDK 初始化 */
	tuya_ble_callback_queue_register(tuya_ble_sdk_callback);/* 注册消息回调函数 */
	tuya_ble_ota_init();                                    /* OTA 初始化 */
	/* ... */
}

TLSR825x 平台为例,OTA 初始化函数如下:

uint32_t tuya_ble_ota_init(void)
{
	s_old_file = &s_old_file_info;            /* 获取已存储的 OTA 文件地址 */
	tuya_ble_ota_info_load();                 /* 加载已存储的 OTA 文件信息 */
	s_ota_state = TUYA_BLE_OTA_STATE_UNKNOWN; /* 设置 OTA 处理的初始状态 */
	return 0;
}

Callback

应用需通过注册的回调函数(无 RTOS 环境下)或者注册的接收队列(RTOS 环境下)接收 OTA 数据,事件 ID 为 TUYA_BLE_CB_EVT_OTA_DATA,在该事件下添加 OTA 数据处理函数。

static void tuya_ble_sdk_callback(tuya_ble_cb_evt_param_t* event)
{
	switch(event->evt) {
	case TUYA_BLE_CB_EVT_OTA_DATA: {
		/* 在 OTA 事件下添加 OTA 处理函数 */
		tuya_ble_ota_handler(&event->ota_data);
	} break;
	/* ... */
}

TLSR825x 平台为例,OTA 数据处理函数如下:

void tuya_ble_ota_handler(tuya_ble_ota_data_t *ota)
{
    /* 设备端响应数据 */
    tuya_ble_ota_response_t rsp;
    rsp.type = ota->type;
    /* 根据接收到的 OTA 数据类型 (OTA 指令) 进行相应处理 */
    switch(ota->type) {
        /* OTA 升级请求 */
        case TUYA_BLE_OTA_REQ: {
            tuya_ble_ota_req_handler(ota->p_data, ota->data_len, &rsp);
        } break;
        /* OTA 升级文件信息 */
        case TUYA_BLE_OTA_FILE_INFO: {
            tuya_ble_ota_file_info_handler(ota->p_data, ota->data_len, &rsp);
        } break;
        /* OTA 升级文件偏移量 */
        case TUYA_BLE_OTA_FILE_OFFSET_REQ: {
            tuya_ble_ota_file_offset_handler(ota->p_data, ota->data_len, &rsp);
        } break;
        /* OTA 升级文件数据 */
        case TUYA_BLE_OTA_DATA: {
            tuya_ble_ota_data_handler(ota->p_data, ota->data_len, &rsp);
        } break;
        /* OTA 升级数据 */
        case TUYA_BLE_OTA_END: {
            tuya_ble_ota_end_handler(ota->p_data, ota->data_len, &rsp);
        } break;
        /* 未知 OTA 指令 */
        case TUYA_BLE_OTA_UNKONWN: {
        } break;
        /* default */
        default: {
        } break;
    }
}

API 说明

tuya_ble_ota_response

位于:tuya_ble_api.h

函数名 tuya_ble_ota_response
函数原型 tuya_ble_status_t tuya_ble_ota_response(tuya_ble_ota_response_t *p_data);
功能概述 OTA 响应指令
参数 p_data [in]:响应数据,数据格式参考本文的 交互协议 章节
返回值
  • TUYA_BLE_SUCCESS:发送成功
  • TUYA_BLE_ERR_INVALID_STATE:状态错误
  • TUYA_BLE_ERR_INVALID_LENGTH:数据长度错误
  • TUYA_BLE_ERR_NO_MEM:内存申请失败
  • TUYA_BLE_ERR_INTERNAL:其他错误
备注 位于 tuya_ble_api.h 文件中,在 OTA 接收数据处理后调用,以向 App 发送响应信息

MCU OTA 移植

如果模组 SDK 中的串口通信方案无法满足您的需求,您可以参考下文来移植自定义方案的 MCU OTA 处理程序。

OTA 请求

APP 向模组发送 OTA 请求数据时:

  • 会触发 SDK 中定义的蓝牙命令事件,处理函数为 tuya_ble_evt_process
  • 如果接收到的是 OTA 相关命令,则执行 OTA 请求数据处理函数 tuya_ble_handle_ota_req
  • 如果是 MCU OTA 任务,则执行 MCU OTA 请求数据处理函数 tuya_ble_uart_common_mcu_ota_data_from_ble_handler,该函数就是 向 MCU 发送 OTA 请求数据 的处理函数。您可以参考函数中的内容,将通信部分替换为自己的通信协议和接口即可。
/* OTA 请求处理 */
static void tuya_ble_handle_ota_req(uint16_t cmd, uint8_t*recv_data, uint32_t recv_len)
{
    /* ... */
    /* MCU OTA */
    if (recv_data[13] == 1) {
        tuya_ble_uart_common_mcu_ota_data_from_ble_handler(cmd, &recv_data[14], data_len-1);
    }
    /* ... */
}

/* 蓝牙命令事件处理 */
void tuya_ble_evt_process(uint16_t cmd, uint8_t*recv_data, uint32_t recv_len)
{
    switch (cmd) {
    /* ... */
    case FRM_OTA_START_REQ:         /* 升级开始 */
    case FRM_OTA_FILE_INFOR_REQ:    /* 升级文件信息 */
    case FRM_OTA_FILE_OFFSET_REQ:   /* 升级文件偏移量 */
    case FRM_OTA_DATA_REQ:          /* 升级文件数据 */
    case FRM_OTA_END_REQ:           /* 升级结束 */
        tuya_ble_handle_ota_req(cmd, recv_data, recv_len);
        break;
    /* ... */
    }
}

OTA 响应

MCU 向模组返回 OTA 响应数据时:

  • 会触发 SDK 中定义的串口命令事件,串口通用命令处理函数为 tuya_ble_uart_common_process
  • 如果接收到的是 OTA 相关命令,则执行 MCU OTA 响应数据处理函数 tuya_ble_uart_common_mcu_ota_data_from_uart_handler,该函数就是 向 App 发送 OTA 响应数据 的入口函数。您可以参考函数中的内容和自定义的通信协议来替换数据解析部分的代码,并在您的 MCU 数据接收函数中调用这部分内容。
  • 数据发送的接口函数为 tuya_ble_commData_send,按要求传入OTA 响应数据即可。
/* 串口通用命令处理 */
void tuya_ble_uart_common_process(uint8_t *p_in_data, uint16_t in_len)
{
    /* ... */
    switch (cmd) {
    case TUYA_BLE_UART_COMMON_MCU_OTA_REQUEST:
    case TUYA_BLE_UART_COMMON_MCU_OTA_FILE_INFO:
    case TUYA_BLE_UART_COMMON_MCU_OTA_FILE_OFFSET:
    case TUYA_BLE_UART_COMMON_MCU_OTA_DATA:
    case TUYA_BLE_UART_COMMON_MCU_OTA_END:
        tuya_ble_uart_common_mcu_ota_data_from_uart_handler(cmd,data_buffer, data_len);
        break;
    /* ... */
    };
}