- 新增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哈希信息
148 lines
7.0 KiB
Python
148 lines
7.0 KiB
Python
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')
|