fix: 修复:改进OTA错误处理和BLE OTA性能
- 重构app.js中的OTA错误处理,以准确报告获取失败而不假设重启,从而实现正确的状态轮询。 - 通过将握手状态封装在SpiLinkState类中来增强SPI主状态管理,提高清晰度并减少直接的状态操作。 引入otaSendAndPoll方法,以更好地处理SPI通信中的命令发送和响应轮询。 - 调整BLE OTA数据包确认逻辑,防止导致固件录变慢的虚假确认,确保仅在实际取得进展时才发送确认。 - 修改确认超时设置,以更好地适应闪存写入速度,减少不重传。
This commit is contained in:
+19
-14
@@ -1144,6 +1144,7 @@ static bool process_esp32_packet(uint8_t cmd, uint16_t seq, uint32_t total_size,
|
||||
}
|
||||
|
||||
// ★ 使用带序号顺序保护的写入:拒绝乱序包并立即 ACK 通知发送端
|
||||
uint32_t beforeReceived = (uint32_t)Esp32OtaCore::instance().getReceived();
|
||||
esp_err_t err = esp32_write_ordered(seq, cmd, &buf[data_offset], data_len);
|
||||
if (err != ESP_OK) {
|
||||
DEBUG_ERR(TAG, "ESP32 OTA 写入失败: seq=%u err=%s",
|
||||
@@ -1152,23 +1153,29 @@ static bool process_esp32_packet(uint8_t cmd, uint16_t seq, uint32_t total_size,
|
||||
return true;
|
||||
}
|
||||
|
||||
DEBUG_DBG(TAG, "ESP32 OTA 写入成功: seq=%u received=%u",
|
||||
seq, (unsigned int)Esp32OtaCore::instance().getReceived());
|
||||
// ★ 仅在实际写入新字节时才触发 ACK:重复包/乱序缓存包不写入 flash,
|
||||
// 若在窗口边界触发 ACK 会携带陈旧字节数,被发送端误判为丢包。
|
||||
uint32_t afterReceived = (uint32_t)Esp32OtaCore::instance().getReceived();
|
||||
bool progressMade = (afterReceived > beforeReceived);
|
||||
|
||||
DEBUG_DBG(TAG, "ESP32 OTA 写入成功: seq=%u received=%u progress=%d",
|
||||
seq, (unsigned int)afterReceived, progressMade ? 1 : 0);
|
||||
|
||||
// 完成判定:以实际按序写入字节数为准。
|
||||
bool isLastPacket = (expected_payload < BLE_OTA_CHUNK_PAYLOAD);
|
||||
bool transferComplete = (total_size > 0 &&
|
||||
Esp32OtaCore::instance().getReceived() >= total_size);
|
||||
bool transferComplete = (total_size > 0 && afterReceived >= total_size);
|
||||
|
||||
// ACK 触发条件
|
||||
if ((((uint32_t)seq + 1U) % BLE_OTA_ACK_WINDOW) == 0U ||
|
||||
transferComplete ||
|
||||
isLastPacket) {
|
||||
// ACK 触发条件:仅在实际写入新字节时触发窗口边界 ACK,
|
||||
// 避免重复包/乱序缓存包在窗口边界发送陈旧 ACK
|
||||
if (progressMade &&
|
||||
((((uint32_t)seq + 1U) % BLE_OTA_ACK_WINDOW) == 0U ||
|
||||
transferComplete ||
|
||||
isLastPacket)) {
|
||||
if (isLastPacket || transferComplete) {
|
||||
DEBUG_INFO(TAG, "ESP32 尾包/完成检测: seq=%u data_len=%zu received=%u total=%" PRIu32,
|
||||
seq, data_len, (unsigned int)Esp32OtaCore::instance().getReceived(), total_size);
|
||||
seq, data_len, (unsigned int)afterReceived, total_size);
|
||||
}
|
||||
sendWindowAck(cmd, seq, (uint32_t)Esp32OtaCore::instance().getReceived());
|
||||
sendWindowAck(cmd, seq, afterReceived);
|
||||
}
|
||||
|
||||
if (transferComplete) {
|
||||
@@ -1226,13 +1233,11 @@ static bool process_gd32_packet(uint8_t cmd, uint16_t seq, uint32_t total_size,
|
||||
// 策略与 ESP32 fallback 路径一致(参考 esp32_write_ordered 行 459-477)。
|
||||
if (seq > 0 && meta.last_seq != (uint32_t)(seq - 1)) {
|
||||
// 重复包:seq <= last_seq(已写入过)
|
||||
// ★ 重复包静默跳过,不发送 ACK:发送端已持有上一窗口的有效 ACK 进度,
|
||||
// 重复包的 ACK 会携带未增长的字节数,被发送端误判为当前窗口丢包。
|
||||
if (seq <= meta.last_seq) {
|
||||
DEBUG_DBG(TAG, "GD32 重复包: seq=%u <= last_seq=%" PRIu32 ",跳过",
|
||||
seq, meta.last_seq);
|
||||
// 重复包不触发 ACK 风暴,只在窗口边界发一次
|
||||
if ((((uint32_t)seq + 1U) % BLE_OTA_ACK_WINDOW) == 0U) {
|
||||
sendWindowAck(cmd, (uint16_t)meta.last_seq, meta.stored_size);
|
||||
}
|
||||
return false; // 外层推进 offset,继续下一包
|
||||
}
|
||||
|
||||
|
||||
@@ -805,7 +805,7 @@ esp_err_t can_mode_handler(httpd_req_t *req)
|
||||
httpd_resp_send(req, resp, len);
|
||||
} else {
|
||||
can_rx_mode_t actual = CAN_RX_MODE_ALL_PASS;
|
||||
int rc = canFdSetRxMode(CAN_RX_MODE_ALL_PASS, &actual, 500);
|
||||
int rc = canFdSetRxMode(CAN_RX_MODE_ALL_PASS, &actual, 2000);
|
||||
char resp[64];
|
||||
int len = snprintf(resp, sizeof(resp),
|
||||
"{\"mode\":%u,\"source\":\"spi\",\"ok\":%s}",
|
||||
@@ -847,7 +847,7 @@ esp_err_t can_mode_handler(httpd_req_t *req)
|
||||
target = CAN_RX_MODE_BRIDGE_0_TO_12;
|
||||
}
|
||||
can_rx_mode_t actual = CAN_RX_MODE_ALL_PASS;
|
||||
int rc = canFdSetRxMode(target, &actual, 500);
|
||||
int rc = canFdSetRxMode(target, &actual, 2000);
|
||||
|
||||
char resp[96];
|
||||
int len = snprintf(resp, sizeof(resp),
|
||||
@@ -909,7 +909,7 @@ esp_err_t can_send_handler(httpd_req_t *req)
|
||||
|
||||
uint8_t resp_data[CAN_MAX_DLC] = {0};
|
||||
int resp_len = canFdSend(ch, ext_id, tx_data, tx_dlc,
|
||||
resp_data, sizeof(resp_data), 1000);
|
||||
resp_data, sizeof(resp_data), 2000);
|
||||
|
||||
char resp[512];
|
||||
if (resp_len >= 0) {
|
||||
|
||||
Reference in New Issue
Block a user