static void ln_ota_handle_download_msg(const OtaDownloadMsg *msg)
{
- static int reset_cnt = 0;
if (!msg) return;
switch (msg->status) {
case OTA_DOWNLOAD_STATUS_PROGRESS:
break;
case OTA_DOWNLOAD_STATUS_FAILED:
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] 下载失败: %s", msg->error_msg);
- reset_cnt++;
- if (reset_cnt < 3) {
- do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_OTA_DOWNLOAD, NULL, 0);
- }
- else {
- uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
- push_ota_status(OTA_UI_STATUS_FAILED);
- }
+ uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
+ push_ota_status(OTA_UI_STATUS_FAILED);
break;
default:
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] 未知状态: %d", msg->status);
HttpClient client = {0};
HttpClientData client_data = {0};
int ret = -1;
- size_t total_written = 0; // 已写入文件的总字节数
+ size_t total_written = 0; // 本次会话写入的字节数
int last_percent = -1; // 上次上报的进度百分比
- // 打开文件准备写入
- FILE *fd = fopen(save_path, "wb+");
+ /* 计算断点偏移:已存在部分文件则续传 */
+ long long resume_offset = 0;
+ {
+ FILE *fexist = fopen(save_path, "rb");
+ if (fexist)
+ {
+ if (fseek(fexist, 0, SEEK_END) == 0)
+ {
+ long pos = ftell(fexist);
+ if (pos > 0)
+ resume_offset = (long long)pos;
+ }
+ fclose(fexist);
+ }
+ }
+ if (resume_offset > 0)
+ {
+ printf("[OTA] resume enabled, offset=%lld\n", resume_offset);
+ if (resume_offset >= (long long)total_size)
+ {
+ printf("[OTA] local file already complete: %lld >= %d\n", resume_offset, total_size);
+ return 0; // 视为已完成
+ }
+ }
+
+ // 打开文件(续传用 ab+,全量用 wb+)
+ FILE *fd = fopen(save_path, resume_offset > 0 ? "ab+" : "wb+");
if (!fd)
{
printf("[OTA] fopen failed for %s:\n", save_path);
return -1;
}
- HTTPC_RESULT prep = ln_http_prepare_auto(&client_data, 2048, LN_CLIENT_PREPARE_SIZE * 4);
+ HTTPC_RESULT prep = ln_http_prepare_auto(&client_data, 2048, LN_CLIENT_PREPARE_SIZE * 2);
if (prep != HTTP_SUCCESS)
{
printf("[OTA] range prepare failed: %d\n", prep);
return -1;
}
+ // 当存在偏移时,设置 Range 头
+ char *header_buf = NULL;
+ if (resume_offset > 0)
+ {
+ header_buf = (char *)malloc(128);
+ if (!header_buf)
+ {
+ HttpClientUnprepare(&client_data);
+ fclose(fd);
+ return -1;
+ }
+ int hdr = snprintf(header_buf, 128, "Range: bytes=%lld-\r\n", resume_offset);
+ if (hdr <= 0)
+ {
+ free(header_buf);
+ HttpClientUnprepare(&client_data);
+ fclose(fd);
+ return -1;
+ }
+ HttpClientSetCustomHeader(&client, header_buf);
+ }
+
// 建立连接(与http_download流程一致)
ret = HttpClientConn(&client, full_url);
if (ret != 0)
{
printf("[OTA] connection failed, ret=0x%x\n", ret);
+ if (header_buf) free(header_buf);
fclose(fd);
HttpClientUnprepare(&client_data);
return ret;
if (ret != 0)
{
printf("[OTA] send request failed, ret=0x%x\n", ret);
+ if (header_buf) free(header_buf);
HttpClientClse(&client);
fclose(fd);
HttpClientUnprepare(&client_data);
return ret;
}
- // 循环接收响应数据(参考http_download的do-while循环)
printf("[OTA] starting to receive data...\n");
- do
+ // 先接收首包以判定状态码;如服务端未按 Range 返回(200),需覆盖写
+ HTTPC_RESULT first_recv = HttpClientRecvResponse(&client, &client_data);
+ if (!(first_recv == HTTP_SUCCESS || first_recv == HTTP_EAGAIN))
+ {
+ printf("[OTA] first recv failed: %d\n", first_recv);
+ if (header_buf) free(header_buf);
+ HttpClientClse(&client);
+ fclose(fd);
+ HttpClientUnprepare(&client_data);
+ return -1;
+ }
+
+ int code = HttpClientGetResponseCode(&client);
+ printf("[OTA] response code: %d (offset=%lld)\n", code, resume_offset);
+ if (code == 200 && resume_offset > 0)
+ {
+ // 服务端未按Range返回,改为全量覆盖
+ fclose(fd);
+ fd = fopen(save_path, "wb+");
+ if (!fd)
+ {
+ if (header_buf) free(header_buf);
+ HttpClientClse(&client);
+ HttpClientUnprepare(&client_data);
+ return -1;
+ }
+ resume_offset = 0;
+ total_written = 0;
+ last_percent = -1;
+ }
+
+ // 写入首块内容(若有)
+ if (client_data.contentBlockLen > 0)
{
- ret = HttpClientRecvResponse(&client, &client_data);
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ln_ota_download_flow_http:%d", ret);
- if (ret == HTTP_SUCCESS || ret == HTTP_EAGAIN)
+ size_t written = fwrite(client_data.responseBuf, 1, client_data.contentBlockLen, fd);
+ if (written != client_data.contentBlockLen)
+ {
+ printf("[OTA] write failed on first block, written=%zu, expected=%d\n", written, client_data.contentBlockLen);
+ if (header_buf) free(header_buf);
+ fclose(fd);
+ HttpClientClse(&client);
+ HttpClientUnprepare(&client_data);
+ return -1;
+ }
+ total_written += written;
+
+ // 进度上报(基于 resume_offset + total_written)
+ long long current_total = resume_offset + (long long)total_written;
+ int percent = (int)((current_total * 100) / total_size);
+ if (percent > 100) percent = 100;
+ if (percent != last_percent)
+ {
+ last_percent = percent;
+ OtaDownloadMsg om = {0};
+ om.status = OTA_DOWNLOAD_STATUS_PROGRESS;
+ om.progress = percent;
+ ln_ota_handle_download_msg(&om);
+ }
+ }
+
+ // 后续接收循环
+ while (client_data.isMore)
+ {
+ HTTPC_RESULT recv_res = HttpClientRecvResponse(&client, &client_data);
+ if (recv_res == HTTP_SUCCESS || recv_res == HTTP_EAGAIN)
{
- // 处理接收到的数据块
if (client_data.contentBlockLen > 0)
{
- // 写入文件(与http_download的写入逻辑一致)
- size_t written = fwrite(client_data.responseBuf, 1,
- client_data.contentBlockLen, fd);
+ size_t written = fwrite(client_data.responseBuf, 1, client_data.contentBlockLen, fd);
if (written != client_data.contentBlockLen)
{
- printf("[OTA] write file failed, written=%zu, expected=%d\n",
- written, client_data.contentBlockLen);
- ret = -1;
- break;
+ printf("[OTA] write failed, written=%zu, expected=%d\n", written, client_data.contentBlockLen);
+ if (header_buf) free(header_buf);
+ fclose(fd);
+ HttpClientClse(&client);
+ HttpClientUnprepare(&client_data);
+ return -1;
}
total_written += written;
- // 进度上报(使用已知的total_size计算)
- int percent = (int)((total_written * 100) / total_size);
- if (percent > 100)
- percent = 100; // 防止超过100%
+
+ long long current_total = resume_offset + (long long)total_written;
+ int percent = (int)((current_total * 100) / total_size);
+ if (percent > 100) percent = 100;
if (percent != last_percent)
{
last_percent = percent;
ln_ota_handle_download_msg(&om);
}
- // 检查是否超过预期总大小
- if (total_written > (size_t)total_size)
+ if (current_total > (long long)total_size)
{
- printf("[OTA] received more than expected! total_written=%zu > total_size=%d\n",
- total_written, total_size);
- ret = -1;
- break;
+ printf("[OTA] received more than expected! current_total=%lld > total_size=%d\n", current_total, total_size);
+ if (header_buf) free(header_buf);
+ fclose(fd);
+ HttpClientClse(&client);
+ HttpClientUnprepare(&client_data);
+ return -1;
}
}
else
{
- // 避免空块忙轮询占用CPU
+ // 避免空块忙轮询
LOS_Msleep(50);
}
}
else
{
- printf("[OTA] receive failed, ret=0x%x\n", ret);
+ printf("[OTA] recv failed: %d\n", recv_res);
break;
}
- } while (client_data.isMore && total_written < (size_t)total_size); // 双重条件判断
- // 检查下载结果(参考http_download的结果校验)
- if (ret == 0 && client.responseCode == 200)
+ }
+
+ int final_code = HttpClientGetResponseCode(&client);
+ long long downloaded = resume_offset + (long long)total_written;
+ printf("[OTA] final code=%d, downloaded=%lld/%d\n", final_code, downloaded, total_size);
+
+ if ((final_code == 200 || final_code == 206) && downloaded == (long long)total_size)
{
- // 验证是否下载完整(使用已知的total_size)
- if (total_written == (size_t)total_size)
- {
- printf("[OTA] download complete! total size: %d bytes\n", total_size);
- ret = 0;
- }
- else
- {
- printf("[OTA] download incomplete! received=%zu, expected=%d\n",
- total_written, total_size);
- ret = -1;
- }
+ ret = 0;
+ printf("[OTA] download complete! total size: %d bytes (%s)\n", total_size, resume_offset > 0 ? "续传resume" : "全量full");
}
else
{
- printf("[OTA] download failed! response code: %d, ret=0x%x\n",
- client.responseCode, ret);
+ ret = -1;
+ printf("[OTA] download incomplete or failed (code=%d)\n", final_code);
}
- printf("[OTA] received=%zu, expected=%d\n",
- total_written, total_size);
- // 资源清理(与http_download保持一致)
+ // 资源清理
+ if (header_buf) free(header_buf);
fclose(fd);
HttpClientClse(&client);
HttpClientUnprepare(&client_data);
-
+
printf("[OTA] download process finished\n");
return ret;
int dres;
if (g_ln_last_package_size > 0)
{
- dres = ln_download_file_to_path(fixed_url, save_path, g_ln_last_package_size);
+ // 若文件存在,则删除文件
+ if(access(save_path, F_OK) == 0)
+ {
+ if(remove(save_path) != 0)
+ {
+ printf("[OTA] remove file failed: %s\n", save_path);
+ return ERRCODE_FAIL;
+ }
+ }
+ for(int i = 0; i < 3; i++)
+ {
+ dres = ln_download_file_to_path(fixed_url, save_path, g_ln_last_package_size);
+ if(dres == 0)
+ {
+ break;
+ }
+ }
}
if (dres != 0)
{