Files
ESP32_COMM/tmp_patch_ble_cpp2.py
T
小龙虾 9ca53ae66e feat(ota): 解耦ESP32 OTA核心逻辑到独立模块并增强BLE控制功能
- 新增ota目录和esp32_ota_core.cpp实现ESP32 OTA核心功能,支持begin/write/finalize操作
- 修改CMakeLists.txt添加ota源文件和包含目录
- 重构ble_ota.cpp将OTA写入/收尾逻辑委托给Esp32OtaCore,移除mbedtls直接引用
- 新增BLE_OTA_CTRL_RESTART_ESP32(0xFA)命令用于重启ESP32设备
- 更新BLE_OTA_CTRL_TRIGGER_ESP32(0xF8)逻辑,要求前端提供SHA-256校验并比对
- 添加SHA-256校验不匹配错误码BLE_OTA_FINISH_ERR_SHA_MISMATCH(0x85)
- 优化OTA收尾流程,设备端读取分区计算SHA-256并与前端提供的哈希比对
- 添加BLE_OTA_NOTIFY_SHA256通知类型用于上报设备端计算的SHA-256值
- 更新app_config.h中的BLE OTA命令描述文档
- 移除BleOta类中的OTA状态变量,仅保留BLE传输层相关状态
- 更新版本构建时间和Git哈希信息
2026-06-14 23:03:28 +08:00

148 lines
7.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import sys
path = r'main\server\ble_ota.cpp'
with open(path, 'r', encoding='utf-8-sig') as f:
data = f.read()
# 1. 文件头注释:补充 0xFA 说明
old = ' * - CTRL (0x0001, Write): 0xF7=触发GD32中继, 0xF8=触发ESP32 OTA升级\n'
new = ' * - CTRL (0x0001, Write): 0xF7=触发GD32中继, 0xF8=触发ESP32 OTA升级(含 32B SHA-256 校验并 reboot),0xFA=重启ESP32\n'
assert old in data, 'header old not found'
data = data.replace(old, new, 1)
# 2. 0xF8 分支:移除 "无 SHA 跳过比对" 路径,强制要求 32B SHA
old_f8 = ''' } else if (buf[0] == BLE_OTA_CTRL_TRIGGER_ESP32) {
if (!Esp32OtaCore::instance().isActive()) {
DEBUG_WARN(TAG, "ESP32 OTA 未激活,无法触发升级");
return 0;
}
if (BleOta::instance().m_esp32RebootPending) {
DEBUG_WARN(TAG, "ESP32 OTA 收尾已在进行中,忽略重复 CTRL");
return 0;
}
// 解析前端 SHA-256: [0xF8] + [32 bytes binary SHA]
char *frontend_sha_hex = nullptr;
if (len >= 33) {
frontend_sha_hex = (char *)malloc(65);
if (frontend_sha_hex) {
for (int i = 0; i < 32; ++i) {
snprintf(&frontend_sha_hex[i * 2], 3, "%02x", buf[1 + i]);
}
frontend_sha_hex[64] = '\\0';
DEBUG_INFO(TAG, "前端 SHA-256: %s", frontend_sha_hex);
}
} else {
// 前端未传 SHA,说明已经走过 0xF9 先校验、收尾不再重复比对
DEBUG_INFO(TAG, "CTRL 0xF8 未传入 SHA-256,finalize 将跳过 SHA 比对与重启前控制流");
}
BleOta::instance().m_esp32RebootPending = true;
BaseType_t ok = xTaskCreate(ble_esp32_finish_and_reboot_task,
"ble_ota_finish",
4096,
frontend_sha_hex, // heap string; task 负责 free
5,
NULL);
if (ok != pdPASS) {
DEBUG_ERR(TAG, "创建 ESP32 OTA 收尾任务失败");
if (frontend_sha_hex) free(frontend_sha_hex);
BleOta::instance().m_esp32RebootPending = false;
} else {
DEBUG_INFO(TAG, "ESP32 OTA 收尾任务已创建(前端 SHA 已传入)");
}
} else if (buf[0] == BLE_OTA_CTRL_VERIFY_SHA256) {
// 仅校验:从 OTA 分区读回计算 SHA-256,通过 0xC1 上报。不 end / 不 set_boot / 不重启。
Esp32OtaCore &core = Esp32OtaCore::instance();
if (!core.isActive()) {
DEBUG_WARN(TAG, "0xF9 请求被拒绝:ESP32 OTA 会话未激活");
sendFinishEvent(BLE_OTA_FINISH_ERR_OTA_END, (uint32_t)ESP_ERR_INVALID_STATE);
return 0;
}
char device_sha_hex[65] = {0};
esp_err_t sha_err = core.computeDeviceSha(device_sha_hex);
if (sha_err != ESP_OK) {
DEBUG_ERR(TAG, "0xF9 请求:从 OTA 分区计算 SHA-256 失败: %s", esp_err_to_name(sha_err));
sendFinishEvent(BLE_OTA_FINISH_ERR_OTA_END, (uint32_t)sha_err);
return 0;
}
uint8_t sha_pkt[33] = {0};
sha_pkt[0] = BLE_OTA_NOTIFY_SHA256;
for (int i = 0; i < 32; ++i) {
unsigned int byte = 0;
sscanf(&device_sha_hex[i * 2], "%02x", &byte);
sha_pkt[1 + i] = (uint8_t)byte;
}
esp_err_t notify_err = BleOta::instance().notifyResponse(sha_pkt, sizeof(sha_pkt));
if (notify_err != ESP_OK) {
DEBUG_WARN(TAG, "0xF9 请求:上报 SHA-256 notify 失败: %s", esp_err_to_name(notify_err));
} else {
DEBUG_INFO(TAG, "0xF9 请求:已上报设备端 SHA-256,前端可继续比对,%s%s",
device_sha_hex, BleOta::instance().m_esp32RebootPending ? "" : "");
}
} else if (buf[0] == BLE_OTA_CTRL_RESTART_ESP32) {'''
new_f8 = ''' } else if (buf[0] == BLE_OTA_CTRL_TRIGGER_ESP32) {
if (!Esp32OtaCore::instance().isActive()) {
DEBUG_WARN(TAG, "ESP32 OTA 未激活,无法触发升级");
return 0;
}
if (BleOta::instance().m_esp32RebootPending) {
DEBUG_WARN(TAG, "ESP32 OTA 收尾已在进行中,忽略重复 CTRL");
return 0;
}
// 强制要求 32B 前端 SHA-256:与 WiFi 流程对齐,设备端读回分区计算并比对,
// 一致走 end+set_boot+reboot,不一致返回 0x85 ERR_SHA_MISMATCH。
if (len < 33) {
DEBUG_WARN(TAG, "CTRL 0xF8 数据长度不足 33(前端 SHA-256 必传),拒绝触发");
sendFinishEvent(BLE_OTA_FINISH_ERR_OTA_END, (uint32_t)ESP_ERR_INVALID_ARG);
return 0;
}
char *frontend_sha_hex = (char *)malloc(65);
if (!frontend_sha_hex) {
DEBUG_ERR(TAG, "CTRL 0xF8 申请内存失败");
sendFinishEvent(BLE_OTA_FINISH_ERR_OTA_END, (uint32_t)ESP_ERR_NO_MEM);
return 0;
}
for (int i = 0; i < 32; ++i) {
snprintf(&frontend_sha_hex[i * 2], 3, "%02x", buf[1 + i]);
}
frontend_sha_hex[64] = '\\0';
DEBUG_INFO(TAG, "前端 SHA-256: %s", frontend_sha_hex);
BleOta::instance().m_esp32RebootPending = true;
BaseType_t ok = xTaskCreate(ble_esp32_finish_and_reboot_task,
"ble_ota_finish",
4096,
frontend_sha_hex, // heap string; task 负责 free
5,
NULL);
if (ok != pdPASS) {
DEBUG_ERR(TAG, "创建 ESP32 OTA 收尾任务失败");
free(frontend_sha_hex);
BleOta::instance().m_esp32RebootPending = false;
} else {
DEBUG_INFO(TAG, "ESP32 OTA 收尾任务已创建(前端 SHA 已传入)");
}
} else if (buf[0] == BLE_OTA_CTRL_RESTART_ESP32) {'''
assert old_f8 in data, '0xF8 block old not found'
data = data.replace(old_f8, new_f8, 1)
# 3. 结尾协议说明注释:删除 0xF9 行
old_tail = ''' // 0xF7 = 触发 GD32 中继
// 0xF8 = 触发 ESP32 本机 OTA 收尾(end + set_boot + reboot,默认不重复校验 SHA,前端需先走 0xF9 确认)
// 0xF9 = 仅从 OTA 分区读回计算 SHA-256,通过 0xC1 notify 上报前端(不 end / 不 reboot)
// 0xFA = 重启 ESP32(配套前端 expectedReboot 自动重连)'''
new_tail = ''' // 0xF7 = 触发 GD32 中继
// 0xF8 = 触发 ESP32 本机 OTA 收尾:设备端读 OTA 分区算 SHA 并与前端 32B SHA 比对,
// 一致走 end+set_boot+reboot,不一致返回 0x85 ERR_SHA_MISMATCH(不重启)
// 0xFA = 重启 ESP32(配套前端 expectedReboot 自动重连)'''
assert old_tail in data, 'tail old not found'
data = data.replace(old_tail, new_tail, 1)
with open(path, 'w', encoding='utf-8-sig') as f:
f.write(data)
print('ble_ota.cpp updated')