feat(ota): 完善OTA传输协议和错误处理机制

- 修改finish ACK验证逻辑,不再接受structured ACK 0xBAC0作为FINISH成功信号
- 移除appRequestBootloader函数的timeout参数,改为内部实现重试机制
- 新增probeBootHandshake函数用于检测GD32是否已处于bootloader模式
- 调整数据包传输中expected_ack值从0xFFFFFFFFU改为0xF0F0F0F0U
- 增加重试次数限制:poll轮询从5次增加到10次,重发次数从3次增加到10次
- 实现FINISH_OTA阶段的重试机制,支持WAIT帧处理和错误恢复
- 在startHandshake和forwardFirmware中添加bootloader探测和状态检查
- 优化APP存活确认失败时的错误处理,添加设备复位操作
- 统一各阶段错误处理逻辑,确保失败时正确清理状态并返回错误码
This commit is contained in:
小龙虾
2026-06-02 03:25:02 +08:00
parent c4d78bdfbc
commit a59364e239
3 changed files with 136 additions and 68 deletions
+27 -17
View File
@@ -349,31 +349,41 @@ esp_err_t SpiMaster::otaPollResponse(uint8_t *resp_type, uint8_t *resp_payload,
return ESP_ERR_TIMEOUT;
}
esp_err_t SpiMaster::appRequestBootloader(uint32_t timeout_ms)
esp_err_t SpiMaster::appRequestBootloader()
{
DEBUG_INFO("SPI", "请求 GD32 APP 进入 Bootloader...");
uint8_t cmd = SPI_APP_ENTER_BOOT_CMD;
esp_err_t ret = transferClocked(&cmd, 1, NULL, 0);
if (ret != ESP_OK) {
DEBUG_WARN("SPI", "发送 Bootloader 请求失败: %s", esp_err_to_name(ret));
return ret;
}
constexpr uint32_t kMaxRetries = 3U;
constexpr uint32_t kPerRetryAckMs = 200U;
constexpr uint32_t kRetryGapMs = 50U;
TickType_t deadline = xTaskGetTickCount() + pdMS_TO_TICKS(timeout_ms);
for (uint32_t retry = 0U; retry < kMaxRetries; ++retry) {
if (retry > 0U) {
DEBUG_WARN("SPI", "Bootloader 请求重发 (%lu/%lu)", (unsigned long)retry, (unsigned long)kMaxRetries);
vTaskDelay(pdMS_TO_TICKS(kRetryGapMs));
}
while (xTaskGetTickCount() <= deadline) {
uint8_t rx = 0;
uint8_t dummy = 0xFF;
ret = transferClocked(&dummy, 1, &rx, 1);
if (ret == ESP_OK && rx == SPI_APP_ENTER_BOOT_ACK_OK) {
DEBUG_INFO("SPI", "GD32 APP 已确认进入 Bootloader");
return ESP_OK;
uint8_t cmd = SPI_APP_ENTER_BOOT_CMD;
esp_err_t ret = transferClocked(&cmd, 1, NULL, 0);
if (ret != ESP_OK) {
DEBUG_WARN("SPI", "发送 Bootloader 请求失败: %s", esp_err_to_name(ret));
continue;
}
TickType_t deadline = xTaskGetTickCount() + pdMS_TO_TICKS(kPerRetryAckMs);
while (xTaskGetTickCount() <= deadline) {
uint8_t rx = 0;
uint8_t dummy = 0xFF;
ret = transferClocked(&dummy, 1, &rx, 1);
if (ret == ESP_OK && rx == SPI_APP_ENTER_BOOT_ACK_OK) {
DEBUG_INFO("SPI", "GD32 APP 已确认进入 Bootloader (retry=%lu)", (unsigned long)retry);
return ESP_OK;
}
vTaskDelay(pdMS_TO_TICKS(10));
}
vTaskDelay(pdMS_TO_TICKS(10));
}
DEBUG_WARN("SPI", "GD32 APP 进入 Bootloader 确认超时");
DEBUG_WARN("SPI", "GD32 APP 进入 Bootloader 确认超时 (retries exhausted)");
return ESP_ERR_TIMEOUT;
}