cat1_27版本升级
authorluozheng <1732036298@qq.com>
Mon, 8 Dec 2025 14:23:22 +0000 (22:23 +0800)
committerluozheng <1732036298@qq.com>
Mon, 8 Dec 2025 14:23:22 +0000 (22:23 +0800)
code/sdk/application/wearable/ln/nativeapp/nativeui/ota/src/OtaPresenter.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp
code/sdk/zhihui/4g/cat1Service/Service/cat1_tcpServer.c
code/sdk/zhihui/4g/cat1Service/include/cat1_tcpServer.h
code/sdk/zhihui/leiniao/imsl_ln/leiniao_api_at.c
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

index 3feb6a5..88b580e 100644 (file)
@@ -25,6 +25,7 @@
 #include "ota/include/OtaUpdateNowView.h"
 #include "ota/include/OtaNightUpdateView.h"
 #include "ota/include/OtaNightUpdateSuccessView.h"
+#include "custom_runtime.h"
 #ifdef SUPPORT_CAT1_SERVICE
 #include "cat1_server.h"
 #endif
@@ -162,7 +163,16 @@ namespace OHOS
                     }
                     //倒计时界面确认,开始升级,定时器停止,进入升级中界面
                     else if (currentView == OtaView::OTA_VIEW_COUNTDOWN) {
-                        do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_OTA_DOWNLOAD, NULL, 0);
+                        // do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_OTA_DOWNLOAD, NULL, 0);
+                        std::string cat1_pyver = uapi_dev_runtime_get_cat1_pyver();
+                        if(cat1_pyver == "PY_SRV_V27")
+                        {
+                            do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_OTA_GET_TASK_CAT1_RUN, NULL, 0);
+                        }
+                        else
+                        {
+                            do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_OTA_DOWNLOAD, NULL, 0);
+                        }
                         OtaModel::GetInstance()->StopCountdownTimer();
                         OtaView::GetInstance()->ChangeView(OtaView::OTA_VIEW_COUNTDOWN, OtaView::OTA_VIEW_UPDATING);
                     }
index 239df79..c469789 100644 (file)
@@ -50,6 +50,8 @@
 #include "ConfigModelC.h"
 #include "ConfigModel.h"
 #include "cmsis_os2.h"
+#include "custom_runtime.h"
+#include "ln_api_interface.h"
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -1608,7 +1610,20 @@ extern "C" {
                     // 需要是绑定状态才更新
                     // if(bind_status == true)
                     // {
-                        ota_update_boot();
+                        std::string cat1_pyver = uapi_dev_runtime_get_cat1_pyver();
+                        if(cat1_pyver == "PY_SRV_V27")
+                        {
+                            push_ota_status(OTA_UI_STATUS_FORCE_START);
+                            const char * text1 = "EG8AK1022V27_1";
+                            ln_ota_get_task_http_CAT1(uapi_ln_get_device_id(), uapi_ln_get_device_token(), text1);
+                            const char * text2 = "EG8AK1022V27_2";
+                            ln_ota_get_task_http_CAT1(uapi_ln_get_device_id(), uapi_ln_get_device_token(), text2);
+                            
+                        }
+                        else
+                        {
+                            ota_update_boot();
+                        }
                     // }   
                     //未绑定状态,联网隐藏网络断开提醒
                     // if(bind_status == false)
@@ -3598,4 +3613,4 @@ extern "C" {
    }
 
 }
- 
\ No newline at end of file
+}
\ No newline at end of file
index 11c599d..ce0133f 100644 (file)
@@ -1371,13 +1371,19 @@ static osTimerId_t modem_ota_timer=NULL;
 
 static uint16 mode_ota_count=0;
 
-
+#include "ln_api_interface.h"
 static void  modem_ota_timer_CallBack(int data_tmp)
 {
     if(old_model_ver!=g_py_ver)
     {
         uint8_t TRANSMIT_DATA=TRANS_FREE;
+
+        #ifdef BOARD_LEINIAO
+        push_ota_status(OTA_UI_STATUS_SUCCESS);
+        shutdown_reboot_prejobs(REBOOT_TYPE);
+        #else
         CustomEventPublish(TOPIC_EVENT_BLE_TRANSMIT,&TRANSMIT_DATA,1);
+        #endif
 
         if(modem_ota_timer){
         osTimerStop(modem_ota_timer);
@@ -1426,13 +1432,15 @@ void star_http_ota_updata(char*buf_1,char* buf_2,uint8_t ver)
     char * send_buf=(char *) malloc(strlen(buf_1)+strlen(buf_2)+40);
     memset(send_buf,0,strlen(buf_1)+strlen(buf_2)+40);
     
-    sprintf(send_buf,"%s and %s",buf_1,buf_2);
+    sprintf(send_buf,"%sand%s",buf_1,buf_2);
     // sprintf(send_buf,"%s and %s","http://snicker.com.cn:8089/FD230/PY_SRV_V19/dfota_1.bin","http://snicker.com.cn:8089/FD230/PY_SRV_V19/dfota_2.bin");
 
     uint8_t TRANSMIT_DATA=START_CAT1_OTA;
-                    
+    
+    #ifdef BOARD_LEINIAO
+    #else
     CustomEventPublish(TOPIC_EVENT_BLE_TRANSMIT,&TRANSMIT_DATA,1);
-
+    #endif
 
     old_model_ver=ver;
 
index ceb53f0..e6cef63 100644 (file)
@@ -71,6 +71,7 @@ errcode_t cat1_tcp_server_init(void);
 void send_bak_mode_toCat1(void);//发送bak fun cmd 
 void ble_tcp_send_msg_toCat1(uint8_t mode,uint8_t cmd,char *content);
 void cat1_ota_send_data(uint8_t Code,char *fileName,uint32_t fileSize,char *data);
+void star_http_ota_updata(char*buf_1,char* buf_2,uint8_t ver);
 //ota_state:
 //CAT1_TCP_START_OTA  开始OTA
 //CAT1_TCP_STOP_OTA  停止OTA
index 9e2a472..52694ae 100644 (file)
@@ -16,6 +16,7 @@
 #include "bts_br_gap.h"
 #include "bts_def.h"
 #include "bluetooth/Ln_Bluetooth_apiC.h"
+#include "cat1_tcpServer.h"
 
 #define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
 #define LN_MAX_ARGC 8
@@ -235,6 +236,36 @@ static uint32_t ln_ota_get_task_at(uint8_t *para, uint32_t paraLen, char *strCom
     return ERRCODE_SUCC;
 }
 
+static uint32_t ln_ota_get_task_new_at(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    LN_UNUSED(para); 
+    LN_UNUSED(paraLen); 
+    LN_UNUSED(strCommonCmd);
+    printf("[LN][OTA_GET_TASK_NEW]\n");
+    uint8_t argv[LN_MAX_ARGC][LN_MAX_ARGV_LEN] = {0};
+    uint32_t argc = 0;
+    (void)ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (argc < 1)
+    {
+        return ERRCODE_FAIL;
+    }
+    const char *text = (const char *)argv[0];
+
+    do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_OTA_GET_TASK_NEW, (char *)text, strlen(text));
+    return ERRCODE_SUCC;
+}
+
+static uint32_t ln_ota_get_task_new_cat1_at(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    LN_UNUSED(para); 
+    LN_UNUSED(paraLen); 
+    LN_UNUSED(strCommonCmd);
+    printf("[LN][OTA_GET_TASK_NEW]\n");
+    star_http_ota_updata(g_ln_last_package_url_new1,g_ln_last_package_url_new2,27);
+    return ERRCODE_SUCC;
+}
+
+
 /* 
  * 职责单一:仅触发"根据最近一次getTask结果下载并校验MD5"的动作
  * 不负责:查询任务/升级/重启/重取token
@@ -1843,6 +1874,8 @@ static const at_cmd_table_t g_ln_api_cmd[] = {
     {(char *)"AT^LN_DEV_CHARACTER", ln_device_get_character_at, (char *)"获取设备角色信息(JSON,GET): AT^LN_DEV_CHARACTER"},
     {(char *)"AT^LN_DEV_USERID", ln_device_get_userid_at, (char *)"获取设备绑定用户ID(JSON,GET): AT^LN_DEV_USERID"},
     {(char *)"AT^LN_OTA_GET_TASK", ln_ota_get_task_at, (char *)"获取OTA升级任务(JSON,GET): AT^LN_OTA_GET_TASK"},
+    {(char *)"AT^LN_OTA_GET_TASK_NEW", ln_ota_get_task_new_at, (char *)"获取OTA升级任务(JSON,GET): AT^LN_OTA_GET_TASK_NEW"},
+    {(char *)"AT^LN_OTA_GET_TASK_NEW_CAT1", ln_ota_get_task_new_cat1_at, (char *)"获取OTA升级任务(JSON,GET): AT^LN_OTA_GET_TASK_NEW"},
     {(char *)"AT^LN_OTA_DOWNLOAD", ln_ota_download_at, (char *)"下载OTA升级包(JSON,GET->下载): AT^LN_OTA_DOWNLOAD"},
     {(char *)"AT^LN_GET_CHAT_STAMINA", ln_get_chat_stamina_at, (char *)"获取对话体力与流量: AT^LN_GET_CHAT_STAMINA"},
     {(char *)"AT^LN_TIMELINE_GET_STATUS", ln_timeline_get_status_at, (char *)"获取时间线状态: AT^LN_TIMELINE_GET_STATUS"},
index 6f89c1a..052f439 100644 (file)
@@ -21,6 +21,7 @@
 #include "custom_utils.h"
 #endif
 #include "bluetooth/Ln_Bluetooth_apiC.h"
+#include "cat1_tcpServer.h"
 // 声明播放器消息处理函数
 
 static app_task_definition_t ln_send_taskcfg = {0};
@@ -48,6 +49,9 @@ char g_ln_character_id[64] = {0};        // 角色ID
 static int g_ln_file_download_type = LN_FILE_DOWNLOAD_TYPE_NONE; // 文件下载类型
 static int g_ln_is_ota_downloading = 0;   // 是否正在下载OTA升级包
 
+char g_ln_last_package_url_new1[256] = {0};
+char g_ln_last_package_url_new2[256] = {0};
+
 /* 简单的字符串读写(以.bin形式读写原始字节,末尾补'\0')*/
 static int ln_read_string_file(const char *file_path, char **out_str)
 {
@@ -1202,6 +1206,29 @@ static void ln_http_server_send_task(void const *arg)
             printf("LN_HTTP_SERVICE_CMD_OTA_GET_TASK:获取OTA升级任务\n");
             ln_ota_get_task_http(uapi_ln_get_device_id(), uapi_ln_get_device_token(), uapi_ln_get_device_version());
         }
+        else if (mail.cmd == LN_HTTP_SERVICE_CMD_OTA_GET_TASK_NEW) //获取特殊CAT1OTA升级任务
+        {
+            if (mail.data && mail.len > 0)
+            {
+               
+                char *source_url = (char *)malloc(mail.len + 1);
+                if (source_url)
+                {
+                    memcpy(source_url, mail.data, mail.len);
+                    source_url[mail.len] = '\0';
+                }
+                if (source_url)
+                {
+                    ln_ota_get_task_http_CAT1(uapi_ln_get_device_id(), uapi_ln_get_device_token(), source_url);
+                    free(source_url);
+                }
+            }
+        }
+        else if (mail.cmd == LN_HTTP_SERVICE_CMD_OTA_GET_TASK_CAT1_RUN) //执行特殊CAT1OTA升级任务
+        {
+            printf("LN_HTTP_SERVICE_CMD_OTA_GET_TASK_CAT1_RUN:获取OTA升级任务\n");
+            star_http_ota_updata(g_ln_last_package_url_new1,g_ln_last_package_url_new2,27);
+        }
         else if (mail.cmd == LN_HTTP_SERVICE_CMD_OTA_DOWNLOAD)
         {
             printf("LN_HTTP_SERVICE_CMD_OTA_DOWNLOAD:下载OTA升级包\n");
index c0cc04c..de32d45 100644 (file)
@@ -145,6 +145,16 @@ typedef struct
 #define LN_HTTP_SERVICE_CMD_CHAT_SESSION_START 0x1016 /* 语音对话流开始 */
 #define LN_HTTP_SERVICE_CMD_CHAT_SESSION_END 0x1017 /* 语音对话流结束 */
 
+/* -------------------------------------------------------------------------- */
+extern char g_ln_last_package_url_new1[256];
+extern char g_ln_last_package_url_new2[256];
+#define LN_HTTP_SERVICE_CMD_OTA_GET_TASK_NEW 0x1018 
+#define LN_HTTP_SERVICE_CMD_OTA_GET_TASK_CAT1_RUN 0x1019 
+uint32_t ln_ota_get_task_http_CAT1(const char *device_id,
+                                const char *device_token,
+                                const char *source_version);
+/* -------------------------------------------------------------------------- */
+
 /* 下载文件相关结构体 */
 typedef struct
 {
index cca83d1..efab4ec 100644 (file)
@@ -7,6 +7,7 @@
 #include "errcode.h"
 #include "custom_utils.h"
 #include "cJSON.h"
+#include "http_file_download_client.h"
 
 /* OTA下载状态枚举(对应时序图中的下载阶段)*/
 typedef enum
@@ -26,6 +27,8 @@ typedef struct
     char md5[65];             /* MD5(来自任务),仅状态为COMPLETED时有效 */
 } OtaDownloadMsg;
 
+static int g_ln_last_reported_percent = -1;     // 最近一次上报的 OTA 下载进度百分比
+
 /* ============================ OTA 内部工具与处理 ============================ */
 static int ln_calc_file_md5_lower_hex(const char *file_path, char out_hex[33])
 {
@@ -94,6 +97,8 @@ static void ln_ota_handle_download_msg(const OtaDownloadMsg *msg)
             break;
         case OTA_DOWNLOAD_STATUS_COMPLETED:
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] 下载完成,文件路径: %s", msg->file_path);
+            // 重置进度记录
+            g_ln_last_reported_percent = -1;
             if (msg->file_path[0] && msg->md5[0]) {
                 WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] 开始MD5校验: %s", msg->md5);
                 int md5_ok = ln_ota_is_md5_ok(msg->file_path, msg->md5);
@@ -133,6 +138,8 @@ 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);
+            // 重置进度记录
+            g_ln_last_reported_percent = -1;
             /* 上报升级失败状态 */
             if (g_ln_last_update_id && g_ln_last_update_id[0] != '\0') {
                 char error_msg[256];
@@ -625,6 +632,105 @@ end:
     return ERRCODE_SUCC;
 }
 
+#if 0
+/* 下载进度回调函数 */
+static int ln_ota_download_progress_callback(const uint8_t *data, uint32_t data_len, uint32_t packet_num)
+{
+    // 获取已下载字节数和总包数
+    uint32_t total_bytes = 0;
+    uint32_t total_packets = 0;
+    if (http_file_download_get_stats(&total_bytes, &total_packets) == 0) {
+        // 计算下载进度百分比
+        if (g_ln_last_package_size > 0) {
+            int percent = (int)((total_bytes * 100) / g_ln_last_package_size);
+            // 确保进度在0-100范围内
+            if (percent < 0) percent = 0;
+            if (percent > 100) percent = 100;
+            
+            // 只有当进度变化时才上报
+            if (percent != g_ln_last_reported_percent) {
+                // 上报进度
+                OtaDownloadMsg om = {0};
+                om.status = OTA_DOWNLOAD_STATUS_PROGRESS;
+                om.progress = percent;
+                ln_ota_handle_download_msg(&om);
+                
+                // 更新上一次上报的进度
+                g_ln_last_reported_percent = percent;
+            }
+        }
+    }
+    return 0;
+}
+
+/* 采用新的HTTP下载接口实现的文件下载函数
+ * 功能:从指定URL下载文件到指定路径(已知总大小)
+ * 参数:full_url - 完整下载URL
+ *       save_path - 保存路径
+ *       total_size - 已知的文件总大小(字节)
+ * 返回:0 - 成功,非0 - 失败
+ */
+
+static int ln_download_file_to_path(const char *full_url, const char *save_path, int total_size)
+{
+    // 参数校验(包含total_size的检查)
+    if (!full_url || !save_path || total_size <= 0)
+    {
+        printf("[OTA] invalid parameters: url=%p, path=%p, total_size=%d\n",
+               full_url, save_path, total_size);
+        return -1;
+    }
+    printf("[OTA] starting download: %s -> %s, total_size=%d bytes\n",
+           full_url, save_path, total_size);
+
+#ifdef SUPPORT_CAT1_SERVICE
+    /* CAT1 网络保活处理 */
+    cat1_api_add_cat1_app_vote();
+    cat1_api_disable_cat1_cmd(0);
+    LOS_Msleep(500); // 等待模块就绪
+#endif
+    uapi_ln_add_vote();
+
+    // 初始化HTTP文件下载服务,传入进度回调函数
+    if (http_file_download_init(ln_ota_download_progress_callback) != 0)
+    {
+        printf("[OTA] http_file_download_init failed\n");
+#ifdef SUPPORT_CAT1_SERVICE
+        cat1_api_remove_cat1_app_vote();
+#endif
+        uapi_ln_remove_vote();
+        return -1;
+    }
+
+    // 开始下载,超时时间设置为300秒(300*1000毫秒)
+    int ret = http_file_download_start(full_url, save_path, 300*1000);
+    
+    // 反初始化HTTP文件下载服务
+    http_file_download_deinit();
+
+    if (ret != 0)
+    {
+        printf("[OTA] http_file_download_start failed, ret=%d\n", ret);
+#ifdef SUPPORT_CAT1_SERVICE
+        cat1_api_remove_cat1_app_vote();
+#endif
+        uapi_ln_remove_vote();
+        return ret;
+    }
+
+    printf("[OTA] download complete! total size: %d bytes\n", total_size);
+
+#ifdef SUPPORT_CAT1_SERVICE
+    cat1_api_remove_cat1_app_vote();
+#endif
+    uapi_ln_remove_vote();
+
+    printf("[OTA] download process finished\n");
+
+    return 0;
+}
+
+#else
 /* 采用http_download风格实现的文件下载函数
  * 功能:从指定URL下载文件到指定路径(已知总大小)
  * 参数:full_url - 完整下载URL
@@ -938,6 +1044,7 @@ static int ln_download_file_to_path(const char *full_url, const char *save_path,
 
     return ret;
 }
+#endif
 
 uint32_t ln_ota_download_flow_http(const char *device_id,
                                    const char *device_token,
@@ -964,6 +1071,9 @@ uint32_t ln_ota_download_flow_http(const char *device_id,
     uapi_ln_set_ota_downloading(1);
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[OTA_DOWNLOAD] 开始OTA升级包下载,设置下载状态保护");
     
+    /* 重置进度记录,确保每次下载从正确状态开始 */
+    g_ln_last_reported_percent = -1;
+    
     /* 上报升级开始状态 */
     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, "开始下载升级包");
@@ -1018,6 +1128,9 @@ uint32_t ln_ota_download_flow_http(const char *device_id,
                 return ERRCODE_FAIL;
             }
         }
+        #ifdef SUPPORT_CAT1_SERVICE
+        cat_sync_timer_control(0);
+        #endif
         for(int i = 0; i < 50; i++)
         {
             printf("[OTA] 当前重试次数: %d\n", i);
@@ -1027,6 +1140,9 @@ uint32_t ln_ota_download_flow_http(const char *device_id,
                 break;
             }
         }
+        #ifdef SUPPORT_CAT1_SERVICE
+        cat_sync_timer_control(1);
+        #endif
     }
     if (dres != 0)
     {
@@ -1107,4 +1223,220 @@ int ln_ws_send_device_upgrade_status_report(const char *update_id, const char *s
     cJSON_free(json_string);
     cJSON_Delete(json);
     return ret;
+}
+
+
+/* 将URL中的https替换为http */
+static inline char *ln_replace_https_to_http(char *url)
+{
+    if (!url)
+        return url;
+    /* 查找https://前缀并替换为http:// */
+    if (strncmp(url, "https://", 8) == 0)
+    {
+        /* 将https://替换为http://,删除第4个字符's' */
+        memmove(url + 4, url + 5, strlen(url + 5) + 1);
+    }
+    return url;
+}
+
+
+static void ln_handle_ota_task_response_CAT1(const char *json_buf, int json_len, char *url)
+{
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "解析OTA升级任务JSON");
+    
+    // 入参校验:url为空时直接返回(避免空指针赋值)
+    if (!url)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[OTA] url参数为空,无法赋值");
+        return;
+    }
+    
+    // 初始化url为空字符串(避免残留数据)
+    *url = '\0';
+    
+    if (!json_buf || json_len <= 0)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[OTA] handle ota task: invalid json");
+        return;
+    }
+    
+    // 拷贝JSON数据并添加结束符
+    char *text = (char *)malloc((size_t)json_len + 1);
+    if (!text)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[OTA] 内存分配失败");
+        return;
+    }
+    memcpy(text, json_buf, (size_t)json_len);
+    text[json_len] = '\0';
+    
+    // 解析JSON根节点
+    cJSON *root = cJSON_Parse(text);
+    if (!root)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[OTA] handle ota task: json parse failed");
+        free(text);
+        return;
+    }
+    
+    // 查找errorCode,若存在则直接返回(无升级或服务端错误)
+    cJSON *errorCode = cJSON_GetObjectItem(root, "errorCode");
+    if (errorCode && !cJSON_IsNull(errorCode))  // 修正:判断errorCode是否为非null(兼容字符串/数字类型)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[OTA] task errorCode存在,无升级包");
+        cJSON_Delete(root);
+        free(text);
+        return;
+    }
+    
+    // 查找data节点
+    cJSON *data = cJSON_GetObjectItem(root, "data");
+    if (!data || !cJSON_IsObject(data))
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[OTA] task data missing");
+        cJSON_Delete(root);
+        free(text);
+        return;
+    }
+    
+    // 查找packageUrl节点并赋值
+    cJSON *packageUrl = cJSON_GetObjectItem(data, "packageUrl");
+    if (packageUrl && cJSON_IsString(packageUrl) && packageUrl->valuestring)
+    {
+        strcpy(url, packageUrl->valuestring);  // 假设url指向的内存空间足够存储packageUrl内容
+        ln_replace_https_to_http(url);
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[OTA] 解析packageUrl成功: %s", url);
+    }
+    else
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[OTA] packageUrl缺失或格式错误");
+    }
+    
+    // 释放资源
+    cJSON_Delete(root);
+    free(text);
+}
+uint32_t ln_ota_get_task_http_CAT1(const char *device_id,
+                              const char *device_token,
+                              const char *source_version)
+{
+    if (!device_id || !device_token || !source_version)
+        return ERRCODE_FAIL;
+
+#ifdef SUPPORT_CAT1_SERVICE
+    /* CAT1 保活 */
+    cat1_api_add_cat1_app_vote();
+    cat1_api_disable_cat1_cmd(0);
+    LOS_Msleep(200);
+#endif
+
+    HttpClient client = (HttpClient){0};
+    HttpClientData clientData = (HttpClientData){0};
+    client.isHttp = false;
+    client.remotePort = 443;
+
+    /* 头:与 device info 一致,额外带 model/version 可辅助服务端日志定位 */
+    size_t hdr_cap = 64 + strlen(device_id) + strlen(device_token) +
+                     (uapi_ln_get_device_model() ? strlen(uapi_ln_get_device_model()) : 5) +
+                     (uapi_ln_get_device_version() ? strlen(uapi_ln_get_device_version()) : 5);
+    char *header_buf = (char *)malloc(hdr_cap + 128);
+    if (!header_buf)
+    {
+#ifdef SUPPORT_CAT1_SERVICE
+        cat1_api_remove_cat1_app_vote();
+#endif
+        return ERRCODE_FAIL;
+    }
+    int hdr = snprintf(header_buf, hdr_cap + 128,
+                       "deviceId: %s\r\n"
+                       "deviceToken: %s\r\n"
+                       "deviceModel: %s\r\n"
+                       "deviceVersion: %s\r\n"
+                       "Content-Type: application/json\r\n",
+                       device_id, device_token,
+                       (uapi_ln_get_device_model() ? uapi_ln_get_device_model() : "AB101"),
+                       (uapi_ln_get_device_version() ? uapi_ln_get_device_version() : "1.0.0"));
+    if (hdr <= 0)
+    {
+        free(header_buf);
+#ifdef SUPPORT_CAT1_SERVICE
+        cat1_api_remove_cat1_app_vote();
+#endif
+        return ERRCODE_FAIL;
+    }
+    HttpClientSetCustomHeader(&client, header_buf);
+
+    HTTPC_RESULT prep = ln_http_prepare_auto(&clientData, 2048, 8 * 1024);
+    if (prep != HTTP_SUCCESS)
+    {
+        printf("[OTA] getTask prepare failed %d\n", prep);
+        free(header_buf);
+#ifdef SUPPORT_CAT1_SERVICE
+        cat1_api_remove_cat1_app_vote();
+#endif
+        return ERRCODE_FAIL;
+    }
+
+    /* 拼 GET URL 参数 */
+    size_t url_cap = strlen(LN_OTA_GET_TASK_URL) + strlen(device_id) + strlen(source_version) + 64;
+    char *url_with_params = (char *)malloc(url_cap);
+    if (!url_with_params)
+    {
+        HttpClientUnprepare(&clientData);
+        free(header_buf);
+#ifdef SUPPORT_CAT1_SERVICE
+        cat1_api_remove_cat1_app_vote();
+#endif
+        return ERRCODE_FAIL;
+    }
+    int ulen = snprintf(url_with_params, url_cap,
+                        "%s?deviceId=%s&sourceVersion=%s",
+                        LN_OTA_GET_TASK_URL, device_id, source_version);
+    if (ulen <= 0 || (size_t)ulen >= url_cap)
+    {
+        HttpClientUnprepare(&clientData);
+        free(header_buf);
+        free(url_with_params);
+#ifdef SUPPORT_CAT1_SERVICE
+        cat1_api_remove_cat1_app_vote();
+#endif
+        return ERRCODE_FAIL;
+    }
+
+    printf("[OTA] GET %s\n", url_with_params);
+
+    HTTPC_RESULT res = HttpClientGetRequest(&client, url_with_params, &clientData);
+    if (res != HTTP_SUCCESS)
+    {
+        printf("[OTA] HttpClientGetRequest error %d\n", res);
+        goto end;
+    }
+
+    int code = HttpClientGetResponseCode(&client);
+    if (code != 200)
+    {
+        goto end;
+    }
+
+    if (clientData.responseBuf && clientData.responseBufLen > 0)
+    {
+        int real_len = clientData.responseContentLen > 0 ? clientData.responseContentLen : clientData.responseBufLen;
+        if(g_ln_last_package_url_new1[0] == '\0')
+            ln_handle_ota_task_response_CAT1(clientData.responseBuf, real_len,g_ln_last_package_url_new1);
+        else if(g_ln_last_package_url_new2[0] == '\0')
+            ln_handle_ota_task_response_CAT1(clientData.responseBuf, real_len,g_ln_last_package_url_new2);
+    }
+
+end:
+    HttpClientUnprepare(&clientData);
+    HttpClientClse(&client);
+    if (header_buf)
+        free(header_buf);
+    if (url_with_params)
+        free(url_with_params);
+#ifdef SUPPORT_CAT1_SERVICE
+    cat1_api_remove_cat1_app_vote();
+#endif
+    return ERRCODE_SUCC;
 }
\ No newline at end of file