yincheng.zhong
昨天 c8240d55741f0ed86099a0a8c616f4fc68372134
STM32H743/APL/OTAUpgrade.c
@@ -12,6 +12,8 @@
#include "HIDO_Debug.h"
#include "HIDO_Util.h"
#include "string.h"
#include "BootMark.h"  // Boot标记管理模块
#include "SoftCRC.h"    // 软件CRC
// 引入AES解密算法
#include "../decryption/aes.h"
@@ -194,7 +196,14 @@
{
    HIDO_INT32 i32Ret;
    
    HIDO_Debug("[OTA] Callback: RespCode=%d, DataLen=%d\r\n", _u32RespCode, _u32Len);
    HIDO_Debug("[OTA] Callback: RespCode=%d, DataLen=%d, State=%d\r\n",
               _u32RespCode, _u32Len, l_stOTAInfo.eState);
    // 如果已经进入解密/校验阶段,忽略后续的下载回调(HTTP连接关闭时的回调)
    if (l_stOTAInfo.eState >= OTA_STATE_DECRYPTING) {
        HIDO_Debug("[OTA] Ignoring download callback (already in decrypt/verify phase)\r\n");
        return HIDO_OK;
    }
    
    // 检查HTTP响应码
    if (_u32RespCode != 200 && _u32RespCode != 206) {
@@ -242,6 +251,9 @@
        i32Ret = OTA_FlashWriteAligned(OTA_ENCRYPTED_FLASH_ADDR, 
                                        l_u32FlashWrittenBytes,
                                        _pu8Data, _u32Len);
        HIDO_Debug("[OTA-DBG] FlashWriteAligned ret=%d\r\n", i32Ret);
        if (i32Ret < 0) {
            HIDO_Debug("[OTA] Flash write failed at offset: 0x%X\r\n", 
                           l_stOTAInfo.u32DownloadedSize);
@@ -263,6 +275,10 @@
        
        // 每10%打印一次进度
        static HIDO_UINT8 s_u8LastLogProgress = 0;
        if (l_stOTAInfo.u8Progress == 0) {
            s_u8LastLogProgress = 0;
        }
        if (l_stOTAInfo.u8Progress >= s_u8LastLogProgress + 10) {
            HIDO_Debug("[OTA] Download progress: %d%% (%d/%d bytes)\r\n", 
                           l_stOTAInfo.u8Progress, 
@@ -272,15 +288,22 @@
        }
    }
    
    HIDO_Debug("[OTA-DBG] Check completion: Downloaded=%d, Total=%d\r\n",
               l_stOTAInfo.u32DownloadedSize, l_stOTAInfo.u32TotalSize);
    // 下载完成
    if (l_stOTAInfo.u32DownloadedSize >= l_stOTAInfo.u32TotalSize && 
        l_stOTAInfo.u32TotalSize > 0) {
        
        HIDO_Debug("[OTA] Download complete check passed, flushing buffer...\r\n");
        // 刷新缓冲区(写入剩余数据)
        if (l_u32FlashWriteBufferLen > 0) {
            HIDO_Debug("[OTA] Flushing %d bytes...\r\n", l_u32FlashWriteBufferLen);
            OTA_FlushFlashWriteBuffer(OTA_ENCRYPTED_FLASH_ADDR, 
                                      l_u32FlashWrittenBytes,
                                      &l_u32FlashWrittenBytes);
            HIDO_Debug("[OTA] Flush completed\r\n");
        }
        
        l_stOTAInfo.eState = OTA_STATE_DOWNLOAD_COMPLETE;
@@ -339,8 +362,8 @@
            
            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);
                HIDO_Debug("[OTA] MCUFlash_Write failed at 0x%08X (TotalWritten=0x%X), ret=%d\r\n",
                          u32FlashAddr, _u32WrittenBytes + u32FlashWrittenThisCall, i32Ret);
                return HIDO_ERR;
            }
            
@@ -365,12 +388,20 @@
                                             HIDO_UINT32 *_pu32GlobalWrittenBytes)
{
    if (l_u32FlashWriteBufferLen > 0) {
        // 剩余部分用0xFF填充到32字节对齐
        HIDO_Debug("[OTA] Flush: bufLen=%d, addr=0x%08X\r\n",
                   l_u32FlashWriteBufferLen, _u32BaseAddr + _u32WrittenBytes);
        // 剩余部分用00xFF填充到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] Calling MCUFlash_Write...\r\n");
        HIDO_INT32 ret = MCUFlash_Write(u32FlashAddr, l_au8FlashWriteBuffer, OTA_FLASH_ALIGN_SIZE);
        HIDO_Debug("[OTA] MCUFlash_Write returned: %d\r\n", ret);
        if (ret != HIDO_OK) {
            HIDO_Debug("[OTA] Flush buffer failed at 0x%08X\r\n", u32FlashAddr);
            return HIDO_ERR;
        }
@@ -389,10 +420,13 @@
/**
 * @brief 启动固件解密
 * @details 判断当前运行的APP,决定目标APP地址,直接解密到目标APP区域
 */
HIDO_INT32 OTA_StartDecrypt(HIDO_VOID)
{
    HIDO_INT32 ret;
    uint32_t vtor;
    uint32_t targetAppAddr;
    
    // 状态检查
    if (l_stOTAInfo.eState != OTA_STATE_DOWNLOAD_COMPLETE) {
@@ -400,11 +434,18 @@
        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);
    // 目标始终是暂存区 (Single Bank with Staging)
    targetAppAddr = BOOT_OTA_STAGING_ADDR;
    HIDO_Debug("[OTA] Target: Staging Area (0x%08X)\r\n", targetAppAddr);
    
    if (MCUFlash_Erase(OTA_DECRYPTED_FLASH_ADDR, OTA_DECRYPTED_FLASH_SIZE) != HIDO_OK) {
    // 保存目标APP地址
    l_stOTAInfo.u32TargetAppAddr = targetAppAddr;
    // 擦除目标APP区域(256KB)
    HIDO_Debug("[OTA] Erasing target APP area: 0x%08X, size: %d KB\r\n",
                    targetAppAddr, BOOT_APP_MAX_SIZE / 1024);
    if (MCUFlash_Erase(targetAppAddr, BOOT_APP_MAX_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;
@@ -426,7 +467,7 @@
    
    // 验证Flash是否已擦除(检查前64字节)
    HIDO_UINT8 au8VerifyBuf[64];
    if (MCUFlash_Read(OTA_DECRYPTED_FLASH_ADDR, au8VerifyBuf, 64) == HIDO_OK) {
    if (MCUFlash_Read(targetAppAddr, au8VerifyBuf, 64) == HIDO_OK) {
        HIDO_BOOL bEraseOk = HIDO_TRUE;
        for (HIDO_UINT32 i = 0; i < 64; i++) {
            if (au8VerifyBuf[i] != 0xFF) {
@@ -484,7 +525,7 @@
    if (l_stOTAInfo.u32DecryptedSize >= l_stOTAInfo.u32TotalSize) {
        // 解密完成,刷新缓冲区
        if (l_u32FlashWriteBufferLen > 0) {
            OTA_FlushFlashWriteBuffer(OTA_DECRYPTED_FLASH_ADDR,
            OTA_FlushFlashWriteBuffer(l_stOTAInfo.u32TargetAppAddr,
                                      l_u32DecryptFlashWrittenBytes,
                                      &l_u32DecryptFlashWrittenBytes);
        }
@@ -531,11 +572,11 @@
                   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);
                   l_stOTAInfo.u32TargetAppAddr, l_u32DecryptFlashWrittenBytes, u32ReadLen);
    }
    
    // 写入解密后的数据
    i32Ret = OTA_FlashWriteAligned(OTA_DECRYPTED_FLASH_ADDR,
    // 写入解密后的数据到目标APP地址
    i32Ret = OTA_FlashWriteAligned(l_stOTAInfo.u32TargetAppAddr,
                                    l_u32DecryptFlashWrittenBytes,
                                    l_au8DecryptBuffer, u32ReadLen);
    if (i32Ret < 0) {
@@ -596,7 +637,7 @@
    HIDO_UINT32 u32SearchLen = l_stOTAInfo.u32TotalSize - u32SearchStart;
    
    // 读取文件末尾数据
    if (MCUFlash_Read(OTA_DECRYPTED_FLASH_ADDR + u32SearchStart, au8SearchBuf, u32SearchLen) != HIDO_OK) {
    if (MCUFlash_Read(l_stOTAInfo.u32TargetAppAddr + 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;
@@ -642,7 +683,7 @@
    
    // 计算校验和(固件数据部分,不包括校验和和结束符)
    for (i = 0; i < u32DataEndPos; i++) {
        if (MCUFlash_Read(OTA_DECRYPTED_FLASH_ADDR + i, &u8Byte, 1) != HIDO_OK) {
        if (MCUFlash_Read(l_stOTAInfo.u32TargetAppAddr + 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;
@@ -653,7 +694,7 @@
    u32CalculatedSum &= 0xFFFFFFFF;
    
    // 读取存储的校验和(0x0D前4字节,小端序)
    if (MCUFlash_Read(OTA_DECRYPTED_FLASH_ADDR + u32ChecksumPos,
    if (MCUFlash_Read(l_stOTAInfo.u32TargetAppAddr + u32ChecksumPos,
                      au8ChecksumBytes, 4) != HIDO_OK) {
        HIDO_Debug("[OTA] Read checksum failed\r\n");
        l_stOTAInfo.eState = OTA_STATE_VERIFY_FAILED;
@@ -675,6 +716,10 @@
        l_stOTAInfo.eState = OTA_STATE_VERIFY_SUCCESS;
        l_stOTAInfo.eLastError = OTA_ERR_NONE;
        HIDO_Debug("[OTA] Firmware verification SUCCESS!\r\n");
        // 校验成功后,更新Boot标记
        OTA_UpdateBootMark();
        return HIDO_OK;
    } else {
        l_stOTAInfo.eState = OTA_STATE_VERIFY_FAILED;
@@ -753,6 +798,14 @@
    
    // 检查下载超时或失败
    if (l_stOTAInfo.eState == OTA_STATE_DOWNLOADING) {
        // 检查是否已经下载完成但状态未更新(可能卡在回调函数中)
        if (l_stOTAInfo.u32DownloadedSize >= l_stOTAInfo.u32TotalSize &&
            l_stOTAInfo.u32TotalSize > 0 &&
            u32ElapsedMs > 5000) {  // 5秒后还没转换状态
            HIDO_Debug("[OTA] WARNING: Download finished but state not updated! Forcing complete...\r\n");
            l_stOTAInfo.eState = OTA_STATE_DOWNLOAD_COMPLETE;
        }
        // 如果超过30秒没有进度,认为下载超时
        if (u32ElapsedMs > OTA_DOWNLOAD_TIMEOUT_MS) {
            HIDO_Debug("[OTA] Download timeout! No data received for %d ms\r\n", u32ElapsedMs);
@@ -764,13 +817,15 @@
        }
    }
    
    // 处理下载失败,尝试重试
    if (l_stOTAInfo.eState == OTA_STATE_DOWNLOAD_FAILED) {
    // 处理失败(下载、解密或校验失败),尝试重试
    if (l_stOTAInfo.eState == OTA_STATE_DOWNLOAD_FAILED ||
        l_stOTAInfo.eState == OTA_STATE_DECRYPT_FAILED ||
        l_stOTAInfo.eState == OTA_STATE_VERIFY_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);
            HIDO_Debug("[OTA] Error detected (State=%d). Retry attempt %d/%d...\r\n",
                       l_stOTAInfo.eState, l_u8RetryCount, OTA_MAX_RETRY_COUNT);
            
            // 重置HTTP客户端状态(关闭之前的连接)
            HIDO_Debug("[OTA] Resetting HTTP client...\r\n");
@@ -788,7 +843,7 @@
            }
        } else {
            // 已达到最大重试次数,彻底放弃
            HIDO_Debug("[OTA] Download failed after %d retries - GIVING UP\r\n", OTA_MAX_RETRY_COUNT);
            HIDO_Debug("[OTA] Operation 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;  // 重置重试计数
@@ -808,3 +863,81 @@
        OTA_ProcessDecryptTask();
    }
}
/**
 * @brief 更新Boot标记(OTA升级成功后调用)
 * @details 根据当前运行的APP,将新固件标记写入另一个APP区域
 */
HIDO_VOID OTA_UpdateBootMark(HIDO_VOID)
{
    int32_t ret;
    BootMark_t bootMark;
    uint32_t targetAppAddr;
    uint32_t firmwareSize;
    uint32_t firmwareCRC;
    HIDO_Debug("[OTA] Updating boot mark...\r\n");
    // 使用解密阶段已确定的目标APP地址 (Staging)
    targetAppAddr = l_stOTAInfo.u32TargetAppAddr;
    // 计算解密后固件的大小(不包含校验和和0x0D 0x0A)
    // 固件实际大小 = u32TotalSize - 4字节校验和 - 2字节结束符
    firmwareSize = l_stOTAInfo.u32TotalSize - 6;
    // 计算固件的CRC32(从暂存区读取)
    uint32_t wordCount = (firmwareSize + 3) / 4;  // 向上取整到32位字
    firmwareCRC = SoftCRC_Calculate((uint32_t *)targetAppAddr, wordCount);
    HIDO_Debug("[OTA] Firmware size: %u bytes, CRC32: 0x%08X\r\n",
               firmwareSize, firmwareCRC);
    // 读取当前Boot标记以获取版本号(如果有的话)
    uint32_t newVersion = 1;
    BootMark_t currentMark;
    if (BootMark_Read(&currentMark) == BOOT_OK) {
        newVersion = currentMark.u32Version + 1;
    }
    // 填充新的Boot标记
    memset(&bootMark, 0, sizeof(BootMark_t));
    bootMark.u32Magic = BOOT_MARK_MAGIC;
    bootMark.u32UpdateFlag = BOOT_UPDATE_PENDING; // 标记为待更新
    bootMark.u32FirmwareSize = firmwareSize;
    bootMark.u32FirmwareCRC = firmwareCRC;
    bootMark.u32Version = newVersion;
    bootMark.u32SrcAddress = targetAppAddr;       // 源:暂存区
    bootMark.u32DstAddress = BOOT_APP_ADDR;       // 目标:APP运行区
    bootMark.u32BootMarkCRC = BootMark_CalculateCRC(&bootMark);
    // 调试:打印Boot标记内容
    HIDO_Debug("[OTA] BootMark before write:\r\n");
    HIDO_Debug("  Magic:    0x%08X\r\n", bootMark.u32Magic);
    HIDO_Debug("  Update:   0x%08X\r\n", bootMark.u32UpdateFlag);
    HIDO_Debug("  Size:     %u\r\n", bootMark.u32FirmwareSize);
    HIDO_Debug("  CRC:      0x%08X\r\n", bootMark.u32FirmwareCRC);
    HIDO_Debug("  Version:  %u\r\n", bootMark.u32Version);
    HIDO_Debug("  Src:      0x%08X\r\n", bootMark.u32SrcAddress);
    HIDO_Debug("  Dst:      0x%08X\r\n", bootMark.u32DstAddress);
    HIDO_Debug("  MarkCRC:  0x%08X\r\n", bootMark.u32BootMarkCRC);
    // 写入Boot标记
    HIDO_Debug("[OTA] Writing boot mark (Request Update)...\r\n");
    ret = BootMark_Write(&bootMark);
    if (ret != BOOT_OK) {
        HIDO_Debug("[OTA] ERROR: Failed to write boot mark: %d\r\n", ret);
        return;
    }
    HIDO_Debug("[OTA] Boot mark updated successfully!\r\n");
    HIDO_Debug("[OTA] System will restart in 2 seconds...\r\n");
    // 等待串口发送完成
    HAL_Delay(2000);
    // 系统重启
    HIDO_Debug("[OTA] Restarting system now!\r\n");
    HAL_Delay(100);  // 等待最后一条日志发送完成
    NVIC_SystemReset();  // 执行系统复位
}