/***************************************************************************** * @file OTAUpgrade.c * @brief 4G OTA固件升级模块实现 * @author AI Assistant * @date 2025-12-20 *****************************************************************************/ #include "OTAUpgrade.h" #include "HTTPClient.h" #include "MCUFlash.h" #include "Internet.h" #include "HIDO_Debug.h" #include "HIDO_Util.h" #include "string.h" // 引入AES解密算法 #include "../decryption/aes.h" /***************************************************************************** * 宏定义 *****************************************************************************/ #define OTA_AES_BLOCK_SIZE 16 // AES加密块大小 #define OTA_FLASH_ALIGN_SIZE 32 // Flash写入对齐大小 #define OTA_DECRYPT_BUFFER_SIZE 512 // 解密缓冲区大小(32的倍数) #define OTA_FILE_TERMINATOR_CR 0x0D // 文件结束符:回车符 #define OTA_FILE_TERMINATOR_LF 0x0A // 文件结束符:换行符 /***************************************************************************** * 本地变量 *****************************************************************************/ static ST_OTAInfo l_stOTAInfo; // OTA升级信息 static HIDO_CHAR l_acDownloadUrl[256]; // 下载URL static HIDO_UINT8 l_au8FlashWriteBuffer[OTA_FLASH_ALIGN_SIZE]; // Flash写入缓冲区 static HIDO_UINT32 l_u32FlashWriteBufferLen = 0; // 缓冲区当前长度 static HIDO_UINT32 l_u32FlashWrittenBytes = 0; // 已写入Flash的字节数(不含缓冲区) // 解密相关变量 static HIDO_UINT8 l_au8DecryptBuffer[OTA_DECRYPT_BUFFER_SIZE]; // 解密缓冲区 static HIDO_UINT8 l_au8AESChainBlock[OTA_AES_BLOCK_SIZE]; // AES CBC模式链接块 static HIDO_BOOL l_bDecryptTaskRunning = HIDO_FALSE; // 解密任务运行标志 static HIDO_UINT32 l_u32DecryptFlashWrittenBytes = 0; // 解密Flash已写入字节数 // 超时和重试相关变量 #define OTA_DOWNLOAD_TIMEOUT_MS 30000 // 下载超时时间:30秒 #define OTA_MAX_RETRY_COUNT 3 // 最大重试次数 static HIDO_UINT32 l_u32LastProgressTick = 0; // 最后一次有进度的时间戳 static HIDO_UINT32 l_u32LastDownloadedSize = 0; // 上次记录的下载大小 static HIDO_UINT8 l_u8RetryCount = 0; // 当前重试次数 /***************************************************************************** * 本地函数声明 *****************************************************************************/ static HIDO_INT32 OTA_HTTPDownloadCallback(HIDO_UINT32 _u32RespCode, ST_HTTPGetFileResponse *_pstResponse, HIDO_UINT8 *_pu8Data, HIDO_UINT32 _u32Len, HIDO_VOID *_pArg); static HIDO_INT32 OTA_FlashWriteAligned(HIDO_UINT32 _u32BaseAddr, HIDO_UINT32 _u32WrittenBytes, const HIDO_UINT8 *_pu8Data, HIDO_UINT32 _u32Len); static HIDO_INT32 OTA_FlushFlashWriteBuffer(HIDO_UINT32 _u32BaseAddr, HIDO_UINT32 _u32WrittenBytes, HIDO_UINT32 *_pu32GlobalWrittenBytes); static HIDO_VOID OTA_ProcessDecryptTask(HIDO_VOID); /***************************************************************************** * 函数实现 *****************************************************************************/ /** * @brief 初始化OTA升级模块 */ HIDO_INT32 OTA_Init(HIDO_VOID) { HIDO_INT32 ret; HIDO_Debug("[OTA] Initializing OTA module...\r\n"); // 确保MCUFlash已初始化 ret = MCUFlash_Init(); if (ret != HIDO_OK) { HIDO_Debug("[OTA] ERROR: MCUFlash_Init failed: %d\r\n", ret); return ret; } // 初始化数据结构 memset(&l_stOTAInfo, 0, sizeof(l_stOTAInfo)); l_stOTAInfo.eState = OTA_STATE_IDLE; l_stOTAInfo.eLastError = OTA_ERR_NONE; memset(l_acDownloadUrl, 0, sizeof(l_acDownloadUrl)); memset(l_au8FlashWriteBuffer, 0xFF, sizeof(l_au8FlashWriteBuffer)); l_u32FlashWriteBufferLen = 0; l_u32FlashWrittenBytes = 0; l_u32DecryptFlashWrittenBytes = 0; l_bDecryptTaskRunning = HIDO_FALSE; HIDO_Debug("[OTA] Module initialized successfully\r\n"); return HIDO_OK; } /** * @brief 启动OTA固件下载 */ HIDO_INT32 OTA_StartDownload(const HIDO_CHAR *_pcUrl) { ST_HTTPGetFileOpt stOpt; // 参数检查 if (_pcUrl == HIDO_NULL || strlen(_pcUrl) == 0) { HIDO_Debug("[OTA] Invalid URL\r\n"); return OTA_ERR_INVALID_PARAM; } // 状态检查 if (l_stOTAInfo.eState != OTA_STATE_IDLE && l_stOTAInfo.eState != OTA_STATE_DOWNLOAD_FAILED) { HIDO_Debug("[OTA] Busy, current state: %d\r\n", l_stOTAInfo.eState); return OTA_ERR_BUSY; } // 网络检查 if (Internet_IsIPReady() != HIDO_TRUE) { HIDO_Debug("[OTA] Network not ready\r\n"); l_stOTAInfo.eLastError = OTA_ERR_NO_NETWORK; return OTA_ERR_NO_NETWORK; } // 保存URL HIDO_UtilSnprintf(l_acDownloadUrl, sizeof(l_acDownloadUrl), "%s", _pcUrl); // 擦除加密固件存储区 HIDO_Debug("[OTA] Erasing encrypted flash area: 0x%08X, size: %d KB\r\n", OTA_ENCRYPTED_FLASH_ADDR, OTA_ENCRYPTED_FLASH_SIZE / 1024); if (MCUFlash_Erase(OTA_ENCRYPTED_FLASH_ADDR, OTA_ENCRYPTED_FLASH_SIZE) != HIDO_OK) { HIDO_Debug("[OTA] Flash erase failed\r\n"); l_stOTAInfo.eState = OTA_STATE_DOWNLOAD_FAILED; l_stOTAInfo.eLastError = OTA_ERR_FLASH_ERASE_FAILED; return OTA_ERR_FLASH_ERASE_FAILED; } // 重置状态 l_stOTAInfo.eState = OTA_STATE_DOWNLOADING; l_stOTAInfo.eLastError = OTA_ERR_NONE; l_stOTAInfo.u32TotalSize = 0; l_stOTAInfo.u32DownloadedSize = 0; l_stOTAInfo.u32DecryptedSize = 0; l_stOTAInfo.u8Progress = 0; l_u32FlashWriteBufferLen = 0; memset(l_au8FlashWriteBuffer, 0xFF, sizeof(l_au8FlashWriteBuffer)); // 初始化超时检测 l_u32LastProgressTick = xTaskGetTickCount(); l_u32LastDownloadedSize = 0; // 配置HTTP下载选项(支持断点续传) memset(&stOpt, 0, sizeof(stOpt)); stOpt.m_u32RangeBegin = 0; // 从头开始下载 stOpt.m_u32RangeEnd = 0; // 下载到文件末尾 // 如果有ETag,使用ETag进行断点续传验证 if (strlen(l_stOTAInfo.acETag) > 0) { HIDO_UtilSnprintf(stOpt.m_acIfRange, sizeof(stOpt.m_acIfRange), "%s", l_stOTAInfo.acETag); } HIDO_Debug("[OTA] Starting download from: %s\r\n", _pcUrl); // 启动HTTP下载 HIDO_INT32 i32Ret = HTTPClient_GetFile((HIDO_CHAR *)_pcUrl, OTA_HTTPDownloadCallback, &stOpt, HIDO_NULL); HIDO_Debug("[OTA] HTTPClient_GetFile returned: %d\r\n", i32Ret); if (i32Ret != HIDO_OK) { HIDO_Debug("[OTA] HTTPClient_GetFile failed - HTTPClient may be busy\r\n"); l_stOTAInfo.eState = OTA_STATE_DOWNLOAD_FAILED; l_stOTAInfo.eLastError = OTA_ERR_HTTP_FAILED; return OTA_ERR_HTTP_FAILED; } return HIDO_OK; } /** * @brief HTTP下载回调函数 */ static HIDO_INT32 OTA_HTTPDownloadCallback(HIDO_UINT32 _u32RespCode, ST_HTTPGetFileResponse *_pstResponse, HIDO_UINT8 *_pu8Data, HIDO_UINT32 _u32Len, HIDO_VOID *_pArg) { HIDO_INT32 i32Ret; HIDO_Debug("[OTA] Callback: RespCode=%d, DataLen=%d\r\n", _u32RespCode, _u32Len); // 检查HTTP响应码 if (_u32RespCode != 200 && _u32RespCode != 206) { HIDO_Debug("[OTA] HTTP error, response code: %d\r\n", _u32RespCode); l_stOTAInfo.eState = OTA_STATE_DOWNLOAD_FAILED; l_stOTAInfo.eLastError = OTA_ERR_HTTP_FAILED; // 标记为需要重试(而不是立即放弃) // Poll函数会检测到DOWNLOAD_FAILED状态并触发重试 return HIDO_ERR; } // 首次回调,获取文件总大小 if (l_stOTAInfo.u32TotalSize == 0 && _pstResponse != HIDO_NULL) { l_stOTAInfo.u32TotalSize = _pstResponse->m_u32RangeTotal; // 检查文件大小是否超过256KB if (l_stOTAInfo.u32TotalSize > OTA_ENCRYPTED_FLASH_SIZE) { HIDO_Debug("[OTA] File too large: %d bytes (max: %d bytes)\r\n", l_stOTAInfo.u32TotalSize, OTA_ENCRYPTED_FLASH_SIZE); l_stOTAInfo.eState = OTA_STATE_DOWNLOAD_FAILED; l_stOTAInfo.eLastError = OTA_ERR_FILE_TOO_LARGE; return HIDO_ERR; } // 保存ETag用于后续断点续传 if (strlen(_pstResponse->m_acETag) > 0) { HIDO_UtilSnprintf(l_stOTAInfo.acETag, sizeof(l_stOTAInfo.acETag), "%s", _pstResponse->m_acETag); } HIDO_Debug("[OTA] File size: %d bytes (%.1f KB), ETag: %s\r\n", l_stOTAInfo.u32TotalSize, l_stOTAInfo.u32TotalSize / 1024.0f, l_stOTAInfo.acETag); } // 接收数据 if (_pu8Data != HIDO_NULL && _u32Len > 0) { // 更新进度时间戳(有数据到达) l_u32LastProgressTick = xTaskGetTickCount(); l_u32LastDownloadedSize = l_stOTAInfo.u32DownloadedSize; // 写入Flash(带对齐处理)- 传递已写入Flash的字节数 i32Ret = OTA_FlashWriteAligned(OTA_ENCRYPTED_FLASH_ADDR, l_u32FlashWrittenBytes, _pu8Data, _u32Len); if (i32Ret < 0) { HIDO_Debug("[OTA] Flash write failed at offset: 0x%X\r\n", l_stOTAInfo.u32DownloadedSize); l_stOTAInfo.eState = OTA_STATE_DOWNLOAD_FAILED; l_stOTAInfo.eLastError = OTA_ERR_FLASH_WRITE_FAILED; return HIDO_ERR; } // 更新下载阶段的Flash写入计数器 l_u32FlashWrittenBytes += i32Ret; l_stOTAInfo.u32DownloadedSize += _u32Len; // 更新进度 if (l_stOTAInfo.u32TotalSize > 0) { l_stOTAInfo.u8Progress = (HIDO_UINT8)((l_stOTAInfo.u32DownloadedSize * 100) / l_stOTAInfo.u32TotalSize); } // 每10%打印一次进度 static HIDO_UINT8 s_u8LastLogProgress = 0; if (l_stOTAInfo.u8Progress >= s_u8LastLogProgress + 10) { HIDO_Debug("[OTA] Download progress: %d%% (%d/%d bytes)\r\n", l_stOTAInfo.u8Progress, l_stOTAInfo.u32DownloadedSize, l_stOTAInfo.u32TotalSize); s_u8LastLogProgress = l_stOTAInfo.u8Progress; } } // 下载完成 if (l_stOTAInfo.u32DownloadedSize >= l_stOTAInfo.u32TotalSize && l_stOTAInfo.u32TotalSize > 0) { // 刷新缓冲区(写入剩余数据) if (l_u32FlashWriteBufferLen > 0) { OTA_FlushFlashWriteBuffer(OTA_ENCRYPTED_FLASH_ADDR, l_u32FlashWrittenBytes, &l_u32FlashWrittenBytes); } l_stOTAInfo.eState = OTA_STATE_DOWNLOAD_COMPLETE; l_stOTAInfo.u8Progress = 100; HIDO_Debug("[OTA] Download completed: %d bytes\r\n", l_stOTAInfo.u32DownloadedSize); } return HIDO_OK; } /** * @brief Flash写入(带32字节对齐处理) * @param _u32BaseAddr Flash基地址(例如0x08100000) * @param _u32WrittenBytes 已成功写入Flash的字节数(不包括缓冲区中的数据) * @param _pu8Data 待写入的数据 * @param _u32Len 数据长度 * @return HIDO_INT32 成功写入Flash的字节数 */ static HIDO_INT32 OTA_FlashWriteAligned(HIDO_UINT32 _u32BaseAddr, HIDO_UINT32 _u32WrittenBytes, const HIDO_UINT8 *_pu8Data, HIDO_UINT32 _u32Len) { HIDO_UINT32 u32WriteLen; HIDO_UINT32 u32Offset = 0; HIDO_UINT32 u32FlashWrittenThisCall = 0; // 本次调用写入Flash的字节数 HIDO_INT32 i32Ret; while (u32Offset < _u32Len) { // 计算可以写入缓冲区的数据长度 u32WriteLen = OTA_FLASH_ALIGN_SIZE - l_u32FlashWriteBufferLen; if (u32WriteLen > (_u32Len - u32Offset)) { u32WriteLen = _u32Len - u32Offset; } // 复制到缓冲区 memcpy(l_au8FlashWriteBuffer + l_u32FlashWriteBufferLen, _pu8Data + u32Offset, u32WriteLen); l_u32FlashWriteBufferLen += u32WriteLen; u32Offset += u32WriteLen; // 缓冲区满了,写入Flash if (l_u32FlashWriteBufferLen >= OTA_FLASH_ALIGN_SIZE) { // 计算实际Flash写入地址 = 基地址 + 历史已写入字节 + 本次调用已写入字节 HIDO_UINT32 u32FlashAddr = _u32BaseAddr + _u32WrittenBytes + u32FlashWrittenThisCall; // 调试:打印第一次写入的详细信息 static HIDO_BOOL s_bFirstWriteLogged = HIDO_FALSE; if (!s_bFirstWriteLogged && u32FlashAddr >= OTA_DECRYPTED_FLASH_ADDR) { HIDO_Debug("[OTA] First decrypt write: Addr=0x%08X, Data[0-7]=%02X %02X %02X %02X %02X %02X %02X %02X\r\n", u32FlashAddr, l_au8FlashWriteBuffer[0], l_au8FlashWriteBuffer[1], l_au8FlashWriteBuffer[2], l_au8FlashWriteBuffer[3], l_au8FlashWriteBuffer[4], l_au8FlashWriteBuffer[5], l_au8FlashWriteBuffer[6], l_au8FlashWriteBuffer[7]); s_bFirstWriteLogged = HIDO_TRUE; } i32Ret = MCUFlash_Write(u32FlashAddr, l_au8FlashWriteBuffer, OTA_FLASH_ALIGN_SIZE); if (i32Ret != HIDO_OK) { HIDO_Debug("[OTA] MCUFlash_Write failed at 0x%08X (TotalWritten=0x%X)\r\n", u32FlashAddr, _u32WrittenBytes + u32FlashWrittenThisCall); return HIDO_ERR; } u32FlashWrittenThisCall += OTA_FLASH_ALIGN_SIZE; l_u32FlashWriteBufferLen = 0; memset(l_au8FlashWriteBuffer, 0xFF, sizeof(l_au8FlashWriteBuffer)); } } // 返回本次调用写入Flash的字节数(由调用者更新相应计数器) return u32FlashWrittenThisCall; } /** * @brief 刷新Flash写入缓冲区(写入剩余数据) * @param _u32BaseAddr Flash基地址 * @param _u32WrittenBytes 已写入的字节数 * @param _pu32GlobalWrittenBytes 全局写入计数器指针(用于更新) */ static HIDO_INT32 OTA_FlushFlashWriteBuffer(HIDO_UINT32 _u32BaseAddr, HIDO_UINT32 _u32WrittenBytes, HIDO_UINT32 *_pu32GlobalWrittenBytes) { if (l_u32FlashWriteBufferLen > 0) { // 剩余部分用0xFF填充到32字节对齐 memset(l_au8FlashWriteBuffer + l_u32FlashWriteBufferLen, 0xFF, OTA_FLASH_ALIGN_SIZE - l_u32FlashWriteBufferLen); HIDO_UINT32 u32FlashAddr = _u32BaseAddr + _u32WrittenBytes; if (MCUFlash_Write(u32FlashAddr, l_au8FlashWriteBuffer, OTA_FLASH_ALIGN_SIZE) != HIDO_OK) { HIDO_Debug("[OTA] Flush buffer failed at 0x%08X\r\n", u32FlashAddr); return HIDO_ERR; } // 更新全局写入计数器 if (_pu32GlobalWrittenBytes != HIDO_NULL) { *_pu32GlobalWrittenBytes += OTA_FLASH_ALIGN_SIZE; } l_u32FlashWriteBufferLen = 0; memset(l_au8FlashWriteBuffer, 0xFF, sizeof(l_au8FlashWriteBuffer)); } return HIDO_OK; } /** * @brief 启动固件解密 */ HIDO_INT32 OTA_StartDecrypt(HIDO_VOID) { HIDO_INT32 ret; // 状态检查 if (l_stOTAInfo.eState != OTA_STATE_DOWNLOAD_COMPLETE) { HIDO_Debug("[OTA] Cannot start decrypt, state: %d\r\n", l_stOTAInfo.eState); return HIDO_ERR; } // 擦除解密固件存储区 HIDO_Debug("[OTA] Erasing decrypted flash area: 0x%08X, size: %d KB\r\n", OTA_DECRYPTED_FLASH_ADDR, OTA_DECRYPTED_FLASH_SIZE / 1024); if (MCUFlash_Erase(OTA_DECRYPTED_FLASH_ADDR, OTA_DECRYPTED_FLASH_SIZE) != HIDO_OK) { HIDO_Debug("[OTA] Flash erase failed\r\n"); l_stOTAInfo.eState = OTA_STATE_DECRYPT_FAILED; l_stOTAInfo.eLastError = OTA_ERR_FLASH_ERASE_FAILED; return OTA_ERR_FLASH_ERASE_FAILED; } HIDO_Debug("[OTA] Flash erased, waiting for stabilization...\r\n"); vTaskDelay(100); // 延迟100ms等待Flash稳定 // 重新初始化Flash(确保擦除后状态正确) ret = MCUFlash_Init(); if (ret != HIDO_OK) { HIDO_Debug("[OTA] Flash re-init failed: %d\r\n", ret); l_stOTAInfo.eState = OTA_STATE_DECRYPT_FAILED; l_stOTAInfo.eLastError = OTA_ERR_FLASH_ERASE_FAILED; return OTA_ERR_FLASH_ERASE_FAILED; } HIDO_Debug("[OTA] Flash re-initialized\r\n"); // 验证Flash是否已擦除(检查前64字节) HIDO_UINT8 au8VerifyBuf[64]; if (MCUFlash_Read(OTA_DECRYPTED_FLASH_ADDR, au8VerifyBuf, 64) == HIDO_OK) { HIDO_BOOL bEraseOk = HIDO_TRUE; for (HIDO_UINT32 i = 0; i < 64; i++) { if (au8VerifyBuf[i] != 0xFF) { bEraseOk = HIDO_FALSE; HIDO_Debug("[OTA] Erase verify FAILED at offset 0x%X: value=0x%02X\r\n", i, au8VerifyBuf[i]); // 打印前16字节内容 HIDO_Debug("[OTA] First 16 bytes: "); for (HIDO_UINT32 j = 0; j < 16; j++) { HIDO_Debug("%02X ", au8VerifyBuf[j]); } HIDO_Debug("\r\n"); break; } } if (bEraseOk) { HIDO_Debug("[OTA] Erase verification PASSED (first 64 bytes all 0xFF)\r\n"); } else { HIDO_Debug("[OTA] WARNING: Flash may not be fully erased, write may fail\r\n"); } } else { HIDO_Debug("[OTA] Erase verification read failed\r\n"); } // 初始化AES解密 aesDecInit(); memset(l_au8AESChainBlock, 0, sizeof(l_au8AESChainBlock)); // CBC模式IV为全0 l_stOTAInfo.eState = OTA_STATE_DECRYPTING; l_stOTAInfo.u32DecryptedSize = 0; l_stOTAInfo.u8Progress = 0; l_u32FlashWriteBufferLen = 0; l_u32DecryptFlashWrittenBytes = 0; // 重置解密Flash写入计数器 memset(l_au8FlashWriteBuffer, 0xFF, sizeof(l_au8FlashWriteBuffer)); l_bDecryptTaskRunning = HIDO_TRUE; HIDO_Debug("[OTA] Decryption started, size: %d bytes\r\n", l_stOTAInfo.u32TotalSize); return HIDO_OK; } /** * @brief 处理解密任务(分块执行,避免阻塞) */ static HIDO_VOID OTA_ProcessDecryptTask(HIDO_VOID) { HIDO_UINT32 u32ReadLen; HIDO_UINT32 i; HIDO_INT32 i32Ret; if (!l_bDecryptTaskRunning) { return; } // 每次处理一块数据(512字节) if (l_stOTAInfo.u32DecryptedSize >= l_stOTAInfo.u32TotalSize) { // 解密完成,刷新缓冲区 if (l_u32FlashWriteBufferLen > 0) { OTA_FlushFlashWriteBuffer(OTA_DECRYPTED_FLASH_ADDR, l_u32DecryptFlashWrittenBytes, &l_u32DecryptFlashWrittenBytes); } l_bDecryptTaskRunning = HIDO_FALSE; l_stOTAInfo.eState = OTA_STATE_DECRYPT_COMPLETE; l_stOTAInfo.u8Progress = 100; HIDO_Debug("[OTA] Decryption completed: %d bytes\r\n", l_stOTAInfo.u32DecryptedSize); return; } // 读取加密数据 u32ReadLen = OTA_DECRYPT_BUFFER_SIZE; if (l_stOTAInfo.u32DecryptedSize + u32ReadLen > l_stOTAInfo.u32TotalSize) { u32ReadLen = l_stOTAInfo.u32TotalSize - l_stOTAInfo.u32DecryptedSize; } i32Ret = MCUFlash_Read(OTA_ENCRYPTED_FLASH_ADDR + l_stOTAInfo.u32DecryptedSize, l_au8DecryptBuffer, u32ReadLen); if (i32Ret != HIDO_OK) { HIDO_Debug("[OTA] Read encrypted flash failed at offset: 0x%X\r\n", l_stOTAInfo.u32DecryptedSize); l_stOTAInfo.eState = OTA_STATE_DECRYPT_FAILED; l_stOTAInfo.eLastError = OTA_ERR_DECRYPT_FAILED; l_bDecryptTaskRunning = HIDO_FALSE; return; } // 调试:打印第一次读取的前16字节 if (l_stOTAInfo.u32DecryptedSize == 0) { HIDO_Debug("[OTA] First encrypted block: %02X %02X %02X %02X %02X %02X %02X %02X\r\n", l_au8DecryptBuffer[0], l_au8DecryptBuffer[1], l_au8DecryptBuffer[2], l_au8DecryptBuffer[3], l_au8DecryptBuffer[4], l_au8DecryptBuffer[5], l_au8DecryptBuffer[6], l_au8DecryptBuffer[7]); } // AES-CBC解密(每16字节一块) for (i = 0; i < u32ReadLen; i += OTA_AES_BLOCK_SIZE) { aesDecrypt(l_au8DecryptBuffer + i, l_au8AESChainBlock); } // 调试:打印第一次解密的前16字节 if (l_stOTAInfo.u32DecryptedSize == 0) { HIDO_Debug("[OTA] First decrypted block: %02X %02X %02X %02X %02X %02X %02X %02X\r\n", l_au8DecryptBuffer[0], l_au8DecryptBuffer[1], l_au8DecryptBuffer[2], l_au8DecryptBuffer[3], l_au8DecryptBuffer[4], l_au8DecryptBuffer[5], l_au8DecryptBuffer[6], l_au8DecryptBuffer[7]); HIDO_Debug("[OTA] Writing to: BaseAddr=0x%08X, WrittenBytes=0x%X, Len=0x%X\r\n", OTA_DECRYPTED_FLASH_ADDR, l_u32DecryptFlashWrittenBytes, u32ReadLen); } // 写入解密后的数据 i32Ret = OTA_FlashWriteAligned(OTA_DECRYPTED_FLASH_ADDR, l_u32DecryptFlashWrittenBytes, l_au8DecryptBuffer, u32ReadLen); if (i32Ret < 0) { HIDO_Debug("[OTA] Write decrypted flash failed at offset: 0x%X\r\n", l_stOTAInfo.u32DecryptedSize); l_stOTAInfo.eState = OTA_STATE_DECRYPT_FAILED; l_stOTAInfo.eLastError = OTA_ERR_FLASH_WRITE_FAILED; l_bDecryptTaskRunning = HIDO_FALSE; return; } // 更新解密阶段的Flash写入计数器 l_u32DecryptFlashWrittenBytes += i32Ret; l_stOTAInfo.u32DecryptedSize += u32ReadLen; // 更新进度 l_stOTAInfo.u8Progress = (HIDO_UINT8)((l_stOTAInfo.u32DecryptedSize * 100) / l_stOTAInfo.u32TotalSize); // 每10%打印一次进度 static HIDO_UINT8 s_u8LastLogProgress = 0; if (l_stOTAInfo.u8Progress >= s_u8LastLogProgress + 10) { HIDO_Debug("[OTA] Decrypt progress: %d%% (%d/%d bytes)\r\n", l_stOTAInfo.u8Progress, l_stOTAInfo.u32DecryptedSize, l_stOTAInfo.u32TotalSize); s_u8LastLogProgress = l_stOTAInfo.u8Progress; } } /** * @brief 启动固件校验 */ HIDO_INT32 OTA_VerifyFirmware(HIDO_VOID) { HIDO_UINT32 u32CalculatedSum = 0; HIDO_UINT32 u32StoredSum = 0; HIDO_UINT32 i; HIDO_UINT8 u8Byte; HIDO_UINT8 au8ChecksumBytes[4]; // 状态检查 if (l_stOTAInfo.eState != OTA_STATE_DECRYPT_COMPLETE) { HIDO_Debug("[OTA] Cannot verify, state: %d\r\n", l_stOTAInfo.eState); return HIDO_ERR; } l_stOTAInfo.eState = OTA_STATE_VERIFYING; HIDO_Debug("[OTA] Verifying firmware checksum...\r\n"); // 文件格式:[固件数据][校验和4字节][0x0D][0x0A] // 从文件末尾向前查找 0x0D 0x0A 结束符 HIDO_UINT32 u32TerminatorPos = 0; // 0x0D的位置 HIDO_BOOL bFoundTerminator = HIDO_FALSE; HIDO_UINT8 au8SearchBuf[64]; // 只搜索末尾64字节 HIDO_UINT32 u32SearchStart = (l_stOTAInfo.u32TotalSize > 64) ? (l_stOTAInfo.u32TotalSize - 64) : 0; HIDO_UINT32 u32SearchLen = l_stOTAInfo.u32TotalSize - u32SearchStart; // 读取文件末尾数据 if (MCUFlash_Read(OTA_DECRYPTED_FLASH_ADDR + u32SearchStart, au8SearchBuf, u32SearchLen) != HIDO_OK) { HIDO_Debug("[OTA] Read flash failed for terminator search\r\n"); l_stOTAInfo.eState = OTA_STATE_VERIFY_FAILED; l_stOTAInfo.eLastError = OTA_ERR_DECRYPT_FAILED; return HIDO_ERR; } // 从后向前搜索 0x0D 0x0A for (i = u32SearchLen; i >= 2; i--) { if (au8SearchBuf[i-2] == OTA_FILE_TERMINATOR_CR && au8SearchBuf[i-1] == OTA_FILE_TERMINATOR_LF) { u32TerminatorPos = u32SearchStart + i - 2; // 0x0D的位置 bFoundTerminator = HIDO_TRUE; HIDO_Debug("[OTA] Found terminator (0x0D 0x0A) at offset: 0x%X\r\n", u32TerminatorPos); break; } } // 未找到结束符 if (!bFoundTerminator) { HIDO_Debug("[OTA] ERROR: Terminator (0x0D 0x0A) not found in file\r\n"); l_stOTAInfo.eState = OTA_STATE_VERIFY_FAILED; l_stOTAInfo.eLastError = OTA_ERR_DECRYPT_FAILED; return HIDO_ERR; } // 校验文件最小长度:至少需要6字节(校验4字节+0x0D+0x0A) if (u32TerminatorPos < 4) { HIDO_Debug("[OTA] ERROR: File too short, terminator at 0x%X\r\n", u32TerminatorPos); l_stOTAInfo.eState = OTA_STATE_VERIFY_FAILED; l_stOTAInfo.eLastError = OTA_ERR_DECRYPT_FAILED; return HIDO_ERR; } // 校验和位置:0x0D前4字节 HIDO_UINT32 u32ChecksumPos = u32TerminatorPos - 4; // 固件数据结束位置:校验和之前 HIDO_UINT32 u32DataEndPos = u32ChecksumPos; HIDO_Debug("[OTA] Firmware data range: 0x0 - 0x%X (%d bytes)\r\n", u32DataEndPos - 1, u32DataEndPos); HIDO_Debug("[OTA] Checksum position: 0x%X - 0x%X\r\n", u32ChecksumPos, u32ChecksumPos + 3); // 计算校验和(固件数据部分,不包括校验和和结束符) for (i = 0; i < u32DataEndPos; i++) { if (MCUFlash_Read(OTA_DECRYPTED_FLASH_ADDR + i, &u8Byte, 1) != HIDO_OK) { HIDO_Debug("[OTA] Read flash failed at offset: 0x%X\r\n", i); l_stOTAInfo.eState = OTA_STATE_VERIFY_FAILED; l_stOTAInfo.eLastError = OTA_ERR_DECRYPT_FAILED; return HIDO_ERR; } u32CalculatedSum += u8Byte; } u32CalculatedSum &= 0xFFFFFFFF; // 读取存储的校验和(0x0D前4字节,小端序) if (MCUFlash_Read(OTA_DECRYPTED_FLASH_ADDR + u32ChecksumPos, au8ChecksumBytes, 4) != HIDO_OK) { HIDO_Debug("[OTA] Read checksum failed\r\n"); l_stOTAInfo.eState = OTA_STATE_VERIFY_FAILED; l_stOTAInfo.eLastError = OTA_ERR_DECRYPT_FAILED; return HIDO_ERR; } // 小端序转换 u32StoredSum = au8ChecksumBytes[0] | (au8ChecksumBytes[1] << 8) | (au8ChecksumBytes[2] << 16) | (au8ChecksumBytes[3] << 24); HIDO_Debug("[OTA] Calculated checksum: 0x%08X\r\n", u32CalculatedSum); HIDO_Debug("[OTA] Stored checksum: 0x%08X\r\n", u32StoredSum); // 对比校验和 if (u32CalculatedSum == u32StoredSum) { l_stOTAInfo.eState = OTA_STATE_VERIFY_SUCCESS; l_stOTAInfo.eLastError = OTA_ERR_NONE; HIDO_Debug("[OTA] Firmware verification SUCCESS!\r\n"); return HIDO_OK; } else { l_stOTAInfo.eState = OTA_STATE_VERIFY_FAILED; l_stOTAInfo.eLastError = OTA_ERR_CHECKSUM_MISMATCH; HIDO_Debug("[OTA] Firmware verification FAILED! Checksum mismatch\r\n"); return OTA_ERR_CHECKSUM_MISMATCH; } } /** * @brief 获取OTA升级信息 */ HIDO_INT32 OTA_GetInfo(ST_OTAInfo *_pstInfo) { if (_pstInfo == HIDO_NULL) { return HIDO_ERR; } memcpy(_pstInfo, &l_stOTAInfo, sizeof(ST_OTAInfo)); return HIDO_OK; } /** * @brief 获取当前OTA状态 */ E_OTAState OTA_GetState(HIDO_VOID) { return l_stOTAInfo.eState; } /** * @brief 获取下载进度百分比 */ HIDO_UINT8 OTA_GetProgress(HIDO_VOID) { return l_stOTAInfo.u8Progress; } /** * @brief 取消当前OTA操作 */ HIDO_INT32 OTA_Cancel(HIDO_VOID) { if (l_stOTAInfo.eState == OTA_STATE_DOWNLOADING) { HTTPClient_Reset(); } l_bDecryptTaskRunning = HIDO_FALSE; l_stOTAInfo.eState = OTA_STATE_IDLE; HIDO_Debug("[OTA] Operation cancelled\r\n"); return HIDO_OK; } /** * @brief 重置OTA模块到空闲状态 */ HIDO_VOID OTA_Reset(HIDO_VOID) { l_bDecryptTaskRunning = HIDO_FALSE; memset(&l_stOTAInfo, 0, sizeof(l_stOTAInfo)); l_stOTAInfo.eState = OTA_STATE_IDLE; l_stOTAInfo.eLastError = OTA_ERR_NONE; memset(l_acDownloadUrl, 0, sizeof(l_acDownloadUrl)); HIDO_Debug("[OTA] Module reset\r\n"); } /** * @brief OTA模块周期性任务 */ HIDO_VOID OTA_Poll(HIDO_VOID) { HIDO_UINT32 u32CurrentTick = xTaskGetTickCount(); HIDO_UINT32 u32ElapsedMs = u32CurrentTick - l_u32LastProgressTick; // 检查下载超时或失败 if (l_stOTAInfo.eState == OTA_STATE_DOWNLOADING) { // 如果超过30秒没有进度,认为下载超时 if (u32ElapsedMs > OTA_DOWNLOAD_TIMEOUT_MS) { HIDO_Debug("[OTA] Download timeout! No data received for %d ms\r\n", u32ElapsedMs); HIDO_Debug("[OTA] Downloaded: %d/%d bytes\r\n", l_stOTAInfo.u32DownloadedSize, l_stOTAInfo.u32TotalSize); // 标记为失败,触发重试逻辑 l_stOTAInfo.eState = OTA_STATE_DOWNLOAD_FAILED; } } // 处理下载失败,尝试重试 if (l_stOTAInfo.eState == OTA_STATE_DOWNLOAD_FAILED) { // 检查是否还有重试机会 if (l_u8RetryCount < OTA_MAX_RETRY_COUNT) { l_u8RetryCount++; HIDO_Debug("[OTA] Retry attempt %d/%d...\r\n", l_u8RetryCount, OTA_MAX_RETRY_COUNT); // 重置HTTP客户端状态(关闭之前的连接) HIDO_Debug("[OTA] Resetting HTTP client...\r\n"); HTTPClient_Reset(); // 重新开始下载 l_stOTAInfo.eState = OTA_STATE_IDLE; vTaskDelay(2000); // 延迟2秒确保连接完全关闭 if (OTA_StartDownload(l_acDownloadUrl) != HIDO_OK) { HIDO_Debug("[OTA] Retry failed to start download\r\n"); l_stOTAInfo.eState = OTA_STATE_DOWNLOAD_FAILED; l_stOTAInfo.eLastError = OTA_ERR_HTTP_FAILED; // 注意:不要在这里return,让它继续循环重试 } } else { // 已达到最大重试次数,彻底放弃 HIDO_Debug("[OTA] Download failed after %d retries - GIVING UP\r\n", OTA_MAX_RETRY_COUNT); l_stOTAInfo.eState = OTA_STATE_IDLE; // 回到空闲状态,停止重试 l_stOTAInfo.eLastError = OTA_ERR_HTTP_FAILED; l_u8RetryCount = 0; // 重置重试计数 } } // 如果下载成功完成,重置重试计数 if (l_stOTAInfo.eState == OTA_STATE_DOWNLOAD_COMPLETE) { if (l_u8RetryCount > 0) { HIDO_Debug("[OTA] Download completed after %d retry(ies)\r\n", l_u8RetryCount); l_u8RetryCount = 0; } } // 处理解密任务 if (l_stOTAInfo.eState == OTA_STATE_DECRYPTING && l_bDecryptTaskRunning) { OTA_ProcessDecryptTask(); } }