雷鸟:添加设备升级状态上报协议,待验证
authorluozheng <1732036298@qq.com>
Sun, 30 Nov 2025 07:10:04 +0000 (15:10 +0800)
committerluozheng <1732036298@qq.com>
Sun, 30 Nov 2025 07:10:04 +0000 (15:10 +0800)
code/sdk/zhihui/leiniao/imsl_ln/ln_api.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api.h
code/sdk/zhihui/leiniao/imsl_ln/ln_api_ota.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api_websocket.c

index 8932f3a..145e2b3 100644 (file)
@@ -40,6 +40,7 @@ char *g_ln_last_package_url = NULL;      // 最近一次查询到的 OTA 包 URL
 char *g_ln_last_target_version = NULL;   // 最近一次查询到的 OTA 包目标版本(动态分配)
 char *g_ln_last_package_md5 = NULL;      // 最近一次查询到的 OTA 包 MD5(动态分配)
 int g_ln_last_package_size = 0;          // 最近一次查询到的 OTA 包大小(字节)
+char *g_ln_last_update_id = NULL;        // 最近一次查询到的 OTA 升级任务ID(动态分配)
 static int g_ln_is_device_bound = 0;     /* 设备绑定状态 */
 char g_ln_device_user_id[64] = {0};      // 设备绑定用户ID
 static int g_ln_is_file_downloading = 0; // 是否正在下载文件
@@ -957,6 +958,32 @@ void ln_ws_process_message(const ws_data_msg_t *data_msg, ws_command_t type)
         /* 服务端对设备蓝牙状态上报的应答,设备端可以记录或处理 */
         break;
     }
+    case WS_CMD_DEVICE_UPGRADE_STATUS_REPORT_ACK:
+    {
+        printf("[WS] DeviceUpgradeStatusReportAck:设备升级状态上报应答\n");
+        /* 服务端对设备升级状态上报的应答,设备端可以记录或处理 */
+        // if (json_str)
+        // {
+        //     cJSON *root = cJSON_Parse(json_str);
+        //     if (root)
+        //     {
+        //         cJSON *data_obj = cJSON_GetObjectItem(root, "data");
+        //         if (data_obj && cJSON_IsObject(data_obj))
+        //         {
+        //             cJSON *success = cJSON_GetObjectItem(data_obj, "success");
+        //             cJSON *message = cJSON_GetObjectItem(data_obj, "message");
+        //             if (success && cJSON_IsBool(success))
+        //             {
+        //                 WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[WS] DeviceUpgradeStatusReportAck: success=%s, message=%s",
+        //                     cJSON_IsTrue(success) ? "true" : "false",
+        //                     (message && cJSON_IsString(message)) ? message->valuestring : "");
+        //             }
+        //         }
+        //         cJSON_Delete(root);
+        //     }
+        // }
+        break;
+    }
     case WS_CMD_PING:
     {
         printf("[WS] Ping\n");
index 5677ccb..29322fe 100644 (file)
@@ -289,7 +289,8 @@ extern char *g_ln_last_saved_path;      /* 最近一次保存的 OTA 包路径
 extern char *g_ln_last_package_url;     /* 最近一次查询到的 OTA 包 URL(动态分配)*/
 extern char *g_ln_last_target_version;  /* 最近一次查询到的 OTA 包目标版本(动态分配)*/
 extern char *g_ln_last_package_md5;     /* 最近一次查询到的 OTA 包 MD5(动态分配)*/
-extern int g_ln_last_package_size;
+extern int g_ln_last_package_size;      /* 最近一次查询到的 OTA 包大小 */
+extern char * g_ln_last_update_id;      /* 最近一次升级ID */
 /* 全局角色配置结构体实例 */
 extern LnCharacterConfig g_ln_character_config;
 /* 全局日程提醒结构体实例 */
@@ -329,6 +330,8 @@ void ln_parse_delete_emoji(const char *json_str, int json_len);
 void ln_emoji_report_status(char *data);
 /* 解析设备升级 */
 void ln_parse_device_upgrade(const char *json_str, int json_len);
+/* 发送设备升级状态上报 */
+int ln_ws_send_device_upgrade_status_report(const char *update_id, const char *status, int progress, const char *msg);
 /* 解析蓝牙连接命令 */
 void ln_parse_bluetooth_connect(const char *json_str, int json_len);
 /* 解析蓝牙解绑命令 */
@@ -446,6 +449,7 @@ typedef enum {
     WS_CMD_SENTENCE_PLAYBACK_COMPLETE, /* 单句语音播放完成 */
     WS_CMD_VAD_INITIALIZED,          /* VAD 服务器初始化完成 */
     WS_CMD_DEVICE_UPGRADE,           /* 设备升级(DeviceUpgrade) */
+    WS_CMD_DEVICE_UPGRADE_STATUS_REPORT_ACK, /* 设备升级状态上报应答(DeviceUpgradeStatusReportAck) */
     WS_CMD_BLUETOOTH_CONNECT,        /* 蓝牙连接(BluetoothConnect) */
     WS_CMD_BLUETOOTH_UNBIND,         /* 蓝牙解绑(BluetoothUnbind) */
     WS_CMD_BLUETOOTH_STATUS_REPORT_ACK, /* 蓝牙状态上报应答(BluetoothStatusReportAck) */
index 1f08501..e614ecd 100644 (file)
@@ -85,6 +85,12 @@ static void ln_ota_handle_download_msg(const OtaDownloadMsg *msg)
         case OTA_DOWNLOAD_STATUS_PROGRESS:
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] 下载进度: %d%%", msg->progress);
             push_ota_progress(msg->progress);
+            /* 上报升级进度 */
+            if (g_ln_last_update_id && g_ln_last_update_id[0] != '\0') {
+                char progress_msg[128];
+                snprintf(progress_msg, sizeof(progress_msg), "升级进度%d%%", msg->progress);
+                ln_ws_send_device_upgrade_status_report(g_ln_last_update_id, "UPGRADING", msg->progress, progress_msg);
+            }
             break;
         case OTA_DOWNLOAD_STATUS_COMPLETED:
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] 下载完成,文件路径: %s", msg->file_path);
@@ -93,11 +99,19 @@ static void ln_ota_handle_download_msg(const OtaDownloadMsg *msg)
                 int md5_ok = ln_ota_is_md5_ok(msg->file_path, msg->md5);
                 if (md5_ok == 1) {
                     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] MD5校验成功,准备重启升级");
+                    /* 上报升级成功状态(注意:设备即将重启,此消息可能无法发送,但尝试发送) */
+                    if (g_ln_last_update_id && g_ln_last_update_id[0] != '\0') {
+                        ln_ws_send_device_upgrade_status_report(g_ln_last_update_id, "SUCCESS", 100, "升级包下载完成,MD5校验成功,准备重启升级");
+                    }
                     uapi_delete_files(LN_TOKEN_FILE);//删除旧版本的token文件
                     push_ota_status(OTA_UI_STATUS_SUCCESS);
                     (void)uaip_cmd_update_request();
                 } else if (md5_ok == 0) {
                     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] MD5校验失败,建议重新下载");
+                    /* 上报升级失败状态 */
+                    if (g_ln_last_update_id && g_ln_last_update_id[0] != '\0') {
+                        ln_ws_send_device_upgrade_status_report(g_ln_last_update_id, "FAILED", 0, "MD5校验失败,建议重新下载");
+                    }
                     uapi_ln_remove_vote();
                     push_ota_status(OTA_UI_STATUS_FAILED);
                     /* 清除OTA下载状态 */
@@ -105,6 +119,10 @@ static void ln_ota_handle_download_msg(const OtaDownloadMsg *msg)
                     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[OTA_DOWNLOAD] MD5校验失败,清除下载状态保护");
                 } else {
                     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] MD5校验出错");
+                    /* 上报升级失败状态 */
+                    if (g_ln_last_update_id && g_ln_last_update_id[0] != '\0') {
+                        ln_ws_send_device_upgrade_status_report(g_ln_last_update_id, "FAILED", 0, "MD5校验出错");
+                    }
                     uapi_ln_remove_vote();
                     push_ota_status(OTA_UI_STATUS_FAILED);
                     /* 清除OTA下载状态 */
@@ -115,6 +133,12 @@ static void ln_ota_handle_download_msg(const OtaDownloadMsg *msg)
             break;
         case OTA_DOWNLOAD_STATUS_FAILED:
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] 下载失败: %s", msg->error_msg);
+            /* 上报升级失败状态 */
+            if (g_ln_last_update_id && g_ln_last_update_id[0] != '\0') {
+                char error_msg[256];
+                snprintf(error_msg, sizeof(error_msg), "下载失败: %s", msg->error_msg);
+                ln_ws_send_device_upgrade_status_report(g_ln_last_update_id, "FAILED", 0, error_msg);
+            }
             uapi_ln_remove_vote();
             push_ota_status(OTA_UI_STATUS_FAILED);
             /* 清除OTA下载状态 */
@@ -218,10 +242,28 @@ static void ln_handle_ota_task_response(const char *json_buf, int json_len)
            (packageMd5 && cJSON_IsString(packageMd5)) ? packageMd5->valuestring : "<null>",
            (description && cJSON_IsString(description)) ? description->valuestring : "<null>");
     /* 记录必要字段供后续 AT^LN_OTA_DOWNLOAD 使用 */
+    if (g_ln_last_update_id) { free(g_ln_last_update_id); g_ln_last_update_id = NULL; }
     if (g_ln_last_target_version) { free(g_ln_last_target_version); g_ln_last_target_version = NULL; }
     if (g_ln_last_package_url) { free(g_ln_last_package_url); g_ln_last_package_url = NULL; }
     if (g_ln_last_package_md5) { free(g_ln_last_package_md5); g_ln_last_package_md5 = NULL; }
     g_ln_last_package_size = 0;
+    
+    /* 保存 updateId,用于状态上报 */
+    if (updateId && (cJSON_IsString(updateId) || cJSON_IsNumber(updateId))) {
+        char update_id_str[64] = {0};
+        if (cJSON_IsString(updateId)) {
+            snprintf(update_id_str, sizeof(update_id_str), "%s", updateId->valuestring);
+        } else if (cJSON_IsNumber(updateId)) {
+            snprintf(update_id_str, sizeof(update_id_str), "%d", (int)updateId->valuedouble);
+        }
+        if (update_id_str[0] != '\0') {
+            size_t len = strlen(update_id_str);
+            g_ln_last_update_id = (char *)malloc(len + 1);
+            if (g_ln_last_update_id) {
+                memcpy(g_ln_last_update_id, update_id_str, len + 1);
+            }
+        }
+    }
     if (targetVersion && cJSON_IsString(targetVersion)) {
         size_t len = strlen(targetVersion->valuestring);
         g_ln_last_target_version = (char *)malloc(len + 1);
@@ -388,6 +430,7 @@ void ln_parse_device_upgrade(const char *json_buf, int json_len)
         description->valuestring);
 
     /* 记录必要字段供后续 AT^LN_OTA_DOWNLOAD 使用 */
+    if (g_ln_last_update_id) { free(g_ln_last_update_id); g_ln_last_update_id = NULL; }
     if (g_ln_last_target_version) { free(g_ln_last_target_version); g_ln_last_target_version = NULL; }
     if (g_ln_last_package_url) { free(g_ln_last_package_url); g_ln_last_package_url = NULL; }
     if (g_ln_last_package_md5) { free(g_ln_last_package_md5); g_ln_last_package_md5 = NULL; }
@@ -407,6 +450,23 @@ void ln_parse_device_upgrade(const char *json_buf, int json_len)
         g_ln_last_package_md5 = (char *)malloc(len + 1);
         if (g_ln_last_package_md5) memcpy(g_ln_last_package_md5, packageMd5->valuestring, len + 1);
     }
+    
+    /* 保存 updateId,用于状态上报 */
+    if (updateId && (cJSON_IsString(updateId) || cJSON_IsNumber(updateId))) {
+        char update_id_str[64] = {0};
+        if (cJSON_IsString(updateId)) {
+            snprintf(update_id_str, sizeof(update_id_str), "%s", updateId->valuestring);
+        } else if (cJSON_IsNumber(updateId)) {
+            snprintf(update_id_str, sizeof(update_id_str), "%d", (int)updateId->valuedouble);
+        }
+        if (update_id_str[0] != '\0') {
+            size_t len = strlen(update_id_str);
+            g_ln_last_update_id = (char *)malloc(len + 1);
+            if (g_ln_last_update_id) {
+                memcpy(g_ln_last_update_id, update_id_str, len + 1);
+            }
+        }
+    }
 
     if (description && cJSON_IsString(description)) {
         const char *description_ = description->valuestring;
@@ -830,6 +890,11 @@ uint32_t ln_ota_download_flow_http(const char *device_id,
     /* 设置OTA下载状态,防止被打断 */
     uapi_ln_set_ota_downloading(1);
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[OTA_DOWNLOAD] 开始OTA升级包下载,设置下载状态保护");
+    
+    /* 上报升级开始状态 */
+    if (g_ln_last_update_id && g_ln_last_update_id[0] != '\0') {
+        ln_ws_send_device_upgrade_status_report(g_ln_last_update_id, "UPGRADING", 0, "开始下载升级包");
+    }
     /* 固定保存到统一升级包路径 */
     size_t sp_cap = strlen(UPG_FILE_NAME) + 1;
     printf("UPG_FILE_NAME:%s\n",UPG_FILE_NAME);
@@ -914,3 +979,59 @@ uint32_t ln_ota_download_flow_http(const char *device_id,
     free(save_path);
     return ERRCODE_SUCC;
 }
+
+/* 发送设备升级状态上报 DeviceUpgradeStatusReport */
+int ln_ws_send_device_upgrade_status_report(const char *update_id, const char *status, int progress, const char *msg)
+{
+    if (ln_ws_get_connection_state() != 2)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Cannot send DeviceUpgradeStatusReport, connection state: %d\n", ln_ws_get_connection_state());
+        return -1;
+    }
+
+    uint32_t timestamp;
+    uapi_get_timestampe_ss(&timestamp);
+
+    cJSON *json = cJSON_CreateObject();
+    if (!json)
+        return -1;
+
+    cJSON_AddStringToObject(json, "deviceId", uapi_ln_get_device_id());
+    cJSON_AddNumberToObject(json, "timestamp", (double)timestamp);
+
+    char message_id[64];
+    snprintf(message_id, sizeof(message_id), "upgrade_status_%u", timestamp);
+    cJSON_AddStringToObject(json, "messageId", message_id);
+    cJSON_AddStringToObject(json, "command", "DeviceUpgradeStatusReport");
+
+    cJSON *data = cJSON_CreateObject();
+    if (!data)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+    cJSON_AddStringToObject(data, "updateId", (update_id && update_id[0]) ? update_id : "");
+    cJSON_AddStringToObject(data, "status", (status && status[0]) ? status : "UPGRADING");
+    
+    /* progress 仅在 status 为 UPGRADING 时有效 */
+    if (status && strcmp(status, "UPGRADING") == 0)
+    {
+        cJSON_AddNumberToObject(data, "progress", progress);
+    }
+    
+    cJSON_AddStringToObject(data, "message", msg ? msg : "");
+    cJSON_AddItemToObject(json, "data", data);
+
+    char *json_string = cJSON_Print(json);
+    if (!json_string)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+
+    int ret = uapi_ws_send_text(json_string);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Sent DeviceUpgradeStatusReport: %s\n", json_string);
+    cJSON_free(json_string);
+    cJSON_Delete(json);
+    return ret;
+}
\ No newline at end of file
index 07946c3..a17e9a2 100644 (file)
@@ -1755,6 +1755,8 @@ static ws_command_t ln_ws_parse_command_string(const char *command_str)
         return WS_CMD_RANDOM_STORY_RESPONSE;
     } else if (strcmp(command_str, "DeviceUpgrade") == 0) {
         return WS_CMD_DEVICE_UPGRADE;
+    } else if (strcmp(command_str, "DeviceUpgradeStatusReportAck") == 0) {
+        return WS_CMD_DEVICE_UPGRADE_STATUS_REPORT_ACK;
     } else if (strcmp(command_str, "BluetoothConnect") == 0) {
         return WS_CMD_BLUETOOTH_CONNECT;
     } else if (strcmp(command_str, "BluetoothUnbind") == 0) {