文件传输

更新时间:2024-04-18 03:09:30下载pdf

智能门锁、智能手表和手环等设备需要更新语音文件、表盘文件等数据,这些数据通常需要 App 下发到智能设备。为了确保文件下发统一,TuyaOS Bluetooth LE SDK 提供固件下发通道接口,应用层只需通过 SDK 提供的文件下发通信接口,按照本文所述的文件下发协议实现即可。

流程图

下图展示了文件传输流程。

文件传输

数据结构

typedef struct {
    UINT8_T  type;
    UINT16_T file_id;
    UINT8_T  id_len;
    UINT8_T *id_buf;
    UINT32_T file_ver;
    UINT32_T file_len;
    UINT8_T  file_md5[TUYA_BLE_FILE_MD5_LEN];

    UINT32_T data_len;
    UINT16_T pkt_id;
    UINT16_T pkt_len;
    UINT16_T pkt_crc16;
} TAL_BLE_FILE_INFO_T;

typedef struct {
    UINT8_T  type;
    UINT16_T file_id;
    UINT8_T  status;
    UINT16_T pkt_maxlen;
    UINT32_T stored_len;
    UINT8_T  stored_md5[TUYA_BLE_FILE_MD5_LEN];
} TAL_BLE_FILE_INFO_RSP_T;

typedef struct {
    UINT8_T  type;
    UINT16_T file_id;
    UINT32_T offset;
} TAL_BLE_FILE_OFFSET_REQ_T;

typedef struct {
    UINT8_T  type;
    UINT16_T file_id;
    UINT32_T offset;
} TAL_BLE_FILE_OFFSET_REP_T;

typedef struct {
    UINT8_T  type;
    UINT16_T file_id;
    UINT16_T pkt_id;
    UINT16_T pkt_len;
    UINT16_T pkt_crc16;
    UINT8_T *data;
} TAL_BLE_FILE_DATA_REQ_T;

typedef struct {
    UINT8_T  type;
    UINT16_T file_id;
    UINT8_T  status;
} TAL_BLE_FILE_DATA_RSP_T;

typedef struct {
    UINT8_T  type;
    UINT16_T file_id;
} TAL_BLE_FILE_END_REQ_T;

typedef struct {
    UINT8_T  type;
    UINT16_T file_id;
    UINT8_T  status;
} TAL_BLE_FILE_END_RSP_T;

typedef struct {
    UINT32_T file_addr; /*file store next addr, cur_file_addr = (file_addr -(file_len/0x1000+1)*0x1000*/
    UINT8_T  type;      /*cur file info */
    UINT16_T file_id;
    UINT32_T file_ver;
    UINT32_T file_len;
    UINT8_T  file_md5[TUYA_BLE_MD5_LEN];
    UINT8_T  id_len;
    UINT8_T  *id_buf;
} TAL_BLE_FILE_INFO_DATA_T;

typedef struct {
    mbedtls_md5_context ctx_storage; //md5 loop cac.
    UINT16_T cur_file_id; //operation data.
} TAL_BLE_FILE_MD5_INFO_T;

API 说明

  1. 应用层通过注册的回调函数 tuya_ble_handle_ble_data_evt 接收数据。

  2. 通过 Event ID 为 TUYA_BLE_EVT_BLE_CMD 的命令,调用 tuya_ble_handle_ble_cmd_evt 进行数据解析。

    以上第 1 步和第 2 步为通用的数据接收解析过程,根据 cmd 进行文件下发数据处理。

  3. 通过 Event ID 为 TUYA_BLE_CB_EVT_FILE_DATA 的命令,调用 tuya_ble_sdk_callback 进行文件下发数据处理,解析数据并准备回复包。

  4. 最后,回复包调用 Event ID 为 TUYA_BLE_EVT_CUSTOM 的通用回调事件进行数据回复。

    由于第 1 步和第 2 步为通用接口,故不在此赘述。文件下发 API 接口主要针对第 3 步和第 4 步进行说明。

tuya_ble_handle_file_req

函数名 tuya_ble_handle_file_req
函数原型 void tuya_ble_handle_file_req(uint16_t cmd,uint8_t*p_recv_data,uint32_t recv_data_len)
功能概述 读取文件下发数据
参数
  • @param[in] cmd Request command
  • @param[in] p_recv_data Pointer to the buffer with received data
  • @param[in] recv_data_len Length of received data
返回值
备注

示例

void tuya_ble_handle_file_req(uint16_t cmd, uint8_t *recv_data, uint32_t recv_len)
{
  ......

    switch (cmd)
    {
    case FRM_FILE_INFOR_REQ:
        cmd_type = TUYA_BLE_FILE_INFO;
        break;
    case FRM_FILE_OFFSET_REQ:
        cmd_type = TUYA_BLE_FILE_OFFSET_REQ;
        break;
    case FRM_FILE_DATA_REQ:
        cmd_type = TUYA_BLE_FILE_DATA;
        break;
    case FRM_FILE_END_REQ:
        cmd_type = TUYA_BLE_FILE_END;
        break;
    default:
        cmd_type = TUYA_BLE_FILE_UNKONWN;
        break;
    }

    event.evt = TUYA_BLE_CB_EVT_FILE_DATA;
    event.file_data.type = cmd_type;
    event.file_data.data_len = data_len;
    event.file_data.p_data = ble_cb_evt_buffer;

    if (tuya_ble_cb_event_send(&event) != 0)
    {
        tuya_ble_free(ble_cb_evt_buffer);
        TUYA_BLE_LOG_ERROR("tuya_ble_handle_file_req-tuya ble send cb event failed.");
    }
  ......
}

tuya_ble_file_response

函数名 tuya_ble_file_response
函数原型 tuya_ble_status_t tuya_ble_file_response(tuya_ble_file_response_t *p_data)
功能概述 文件下发数据响应
参数 p_data[in]:文件下发响应数据
返回值
  • TUYA_BLE_SUCCESS:成功
  • TUYA_BLE_ERR_INVALID_STATE:无效状态,不能启动文件传输流程,例如当前蓝牙未连接
  • TUYA_BLE_ERR_INVALID_LENGTH:数据长度错误
  • TUYA_BLE_ERR_NO_MEM:内存申请失败
  • TUYA_BLE_ERR_NO_EVENT:队列空间满
备注 在设备接收到 App 的文件下发数据命令后,需要调用该 API 进行响应。

示例

tuya_ble_status_t tuya_ble_file_response(tuya_ble_file_response_t *p_data)
{
   ......

    p_buffer = tuya_ble_malloc(sizeof(tuya_ble_file_response_t) + p_data->data_len);

    if(p_buffer)
    {
        p_res_data = (tuya_ble_file_response_t*)p_buffer;
        p_res_data->p_data = p_buffer + sizeof(tuya_ble_file_response_t);
        p_res_data->data_len = p_data->data_len;
        p_res_data->type = p_data->type;
        memcpy(p_res_data->p_data,p_data->p_data,p_data->data_len);
    }
    else
    {
       return TUYA_BLE_ERR_NO_MEM;
    }

    custom_evt.evt_id = 0;//res
    custom_evt.data = p_res_data;
    custom_evt.custom_event_handler = tuya_ble_handle_file_response_evt;

    TUYA_BLE_LOG_HEXDUMP_DEBUG("custom_data",(uint8_t*)p_res_data->p_data,p_res_data->data_len);

    if (tuya_ble_custom_event_send(custom_evt) != 0)
    {
        tuya_ble_free(p_buffer);
        return TUYA_BLE_ERR_NO_EVENT;
    }

    return TUYA_BLE_SUCCESS;
}
    if (rsp_flag)
    {
        tuya_ble_bulk_data_response(&rsp_data);
    }
}

回调函数

tuya_ble_sdk 通过消息(RTOS 架构下)或者应用层注册的回调函数(无 RTOS 架构下)向应用层发送消息(状态、数据等)。

当 App 向设备下发文件数据命令后,tuya_ble_sdk 会向应用层发送如下的文件下发回调事件。

TUYA_BLE_CB_EVT_FILE_DATA

Event TUYA_BLE_CB_EVT_FILE_DATA
对应数据结构 tuya_ble_bulk_data_request_t
描述 文件下发通道数据请求回调事件
备注 用户可在该回调事件下,处理文件下发数据命令

数据结构

typedef enum
{
    TUYA_BLE_FILE_INFO,            /**< 下发文件信息*/
    TUYA_BLE_FILE_OFFSET_REQ,    /**< 下发文件偏移*/
    TUYA_BLE_FILE_DATA,            /**< 下发文件数据*/
    TUYA_BLE_FILE_END,            /**< 下发文件完成*/
    TUYA_BLE_FILE_UNKONWN,        /**< 其他*/
} tuya_ble_file_data_type_t;

typedef struct {
    tuya_ble_file_data_type_t type;
    uint16_t data_len;
    uint8_t *p_data;
} tuya_ble_file_response_t;

示例

static void tuya_ble_sdk_callback(tuya_ble_cb_evt_param_t *event)
{
    switch (event->evt)
    {
        //...

       case TUYA_BLE_CB_EVT_FILE_DATA: {
#if (TUYA_BLE_FILE_ENABLE != 0)
            TUYA_APP_LOG_INFO("TUYA_BLE_CB_EVT_FILE_DATA");
            tuya_ble_file_handler(&event->file_data);
#endif
        } break;

        //...
    }
}

应用示例

void tuya_ble_file_handler(tuya_ble_file_data_t *file)
{
    tuya_ble_file_response_t rsp;
    rsp.type = file->type;

    if(file->type != TUYA_BLE_FILE_DATA) {
        TUYA_APP_LOG_INFO("file_type: %d", file->type);
        TUYA_APP_LOG_HEXDUMP_INFO("file_data", file->p_data, file->data_len);
    }

    switch (file->type)
    {
        case TUYA_BLE_FILE_INFO: {
            tuya_ble_file_info_handler(file->p_data, file->data_len, &rsp);
        } break;

        case TUYA_BLE_FILE_OFFSET_REQ: {
            tuya_ble_file_offset_handler(file->p_data, file->data_len, &rsp);
        } break;

        case TUYA_BLE_FILE_DATA: {
            tuya_ble_file_data_handler(file->p_data, file->data_len, &rsp);
        } break;

        case TUYA_BLE_FILE_END: {
            tuya_ble_file_end_handler(file->p_data, file->data_len, &rsp);
        } break;

        case TUYA_BLE_FILE_UNKONWN: {
        } break;

        default: {
        } break;
    }
}

使用方法

前置条件

  • 测试 PID:ndhihx1m
  • 您已经下载了智能生活 App。
  • 您的设备已完成配网。

操作步骤

  1. 进入设备面板,单击 设置 选项。

    文件传输
  2. 门锁语言 选项显示 未设置语言状态,单击该选项进入语言状态选择。

    文件传输
  3. 选择想要的语言,下载并使用。

    文件传输
  4. 传输开始,等待传输结束。

    文件传输
  5. 传输完成后,语音包显示为 使用中,表示文件下发流程已经成功完成。

    文件传输

支持与帮助

在开发过程遇到问题,您可以登录 TuyaOS 开发者论坛 TuyaOS-蓝牙设备开发 版块进行沟通咨询。

咨询前,建议首先查阅 官方资料 或参考已有帖子,并认真阅读 发帖规范