refactor: 清理遗留死代码(−353 行)
仓库经多轮迭代积累了不少不再被引用的中间件代码。本次以当前前端依赖的
HTTP 端点为基准(/system/status、/logs、/can/send、/spi/send、/ota/upload、
/ota/update、/ota/relay、/restart),移除以下模块的未引用代码:
- main/transport/protocol.{h,cpp}(−257 行)
* 移除 CMD_* / ACK_* 宏(CMD_HANDSHAKE_REQ 等 16 个)
* 移除未引用方法:crc16Modbus、buildFrame、parseFrame、aesEncrypt、
aesDecrypt、sessionEncrypt、sessionDecrypt、generateRandomNonce
* 保留 init / scrambleGenerate / sessionKeyInit / sessionKeyClear
(被 ota_relay 实际调用)
- main/relay/ota_relay.{h,cpp}(−84 行)
* 移除未引用方法:startHandshake、probeBootHandshake、isStructuredAckWithPayload
* 移除未使用枚举值:RELAY_HANDSHAKE_IDLE、RELAY_RECEIVING、RELAY_TRANSFER_DONE
* 移除字段 ota_meta_t.chunk_count 与宏 OTA_META_NVS_KEY
- main/server/wifi_ota.cpp(−255 行)
* 移除 6 个未被前端调用的 HTTP 端点:/health、/wifi/status、/can/status、
/ota/status、/ota/esp32_status、/api/version
* 移除其处理器与路由注册
* 移除 mbedtls/private/sha256.h 直接引用(SHA-256 已委托 Esp32OtaCore)
- main/server/ble_ota.cpp、main/relay/ota_relay.cpp
* 同步移除 chunk_count 引用
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
#define FW_VERSION_STRING "0.3.12"
|
||||
|
||||
// 编译时间
|
||||
#define BUILD_TIME "2026-06-14 22:46:58"
|
||||
#define BUILD_TIME "2026-06-14 23:55:14"
|
||||
|
||||
// Git 信息
|
||||
#define GIT_HASH "2caf10b"
|
||||
#define GIT_HASH "unknown"
|
||||
|
||||
@@ -201,9 +201,6 @@ bool OtaRelay::isFinishPlainAck(const uint8_t *payload, size_t len)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OtaRelay::isStructuredAckWithPayload(const uint8_t *payload, size_t len)
|
||||
{ return payload && len >= 6U && payload[0] == 0xBAU && payload[1] == 0xC0U; }
|
||||
|
||||
esp_err_t OtaRelay::pollUntilExpectedAckShape(const char *stage,
|
||||
uint8_t *resp_type, uint8_t *resp_payload,
|
||||
size_t resp_max, size_t *resp_len,
|
||||
@@ -306,7 +303,6 @@ esp_err_t OtaRelay::metaLoad(ota_meta_t *meta)
|
||||
if (nvs_get_u32(handle, "total_size", &val) == ESP_OK) meta->total_size = val;
|
||||
if (nvs_get_u32(handle, "stored_size", &val) == ESP_OK) meta->stored_size = val;
|
||||
if (nvs_get_u32(handle, "last_seq", &val) == ESP_OK) meta->last_seq = val;
|
||||
if (nvs_get_u32(handle, "chunk_count", &val) == ESP_OK) meta->chunk_count = val;
|
||||
|
||||
size_t sha_len = sizeof(meta->checksum);
|
||||
if (nvs_get_blob(handle, "checksum", meta->checksum, &sha_len) == ESP_OK && sha_len == sizeof(meta->checksum)) {
|
||||
@@ -338,7 +334,6 @@ esp_err_t OtaRelay::metaSave(const ota_meta_t *meta)
|
||||
nvs_set_u32(handle, "total_size", meta->total_size);
|
||||
nvs_set_u32(handle, "stored_size", meta->stored_size);
|
||||
nvs_set_u32(handle, "last_seq", meta->last_seq);
|
||||
nvs_set_u32(handle, "chunk_count", meta->chunk_count);
|
||||
nvs_set_blob(handle, "checksum", meta->checksum, sizeof(meta->checksum));
|
||||
err = nvs_commit(handle);
|
||||
nvs_close(handle);
|
||||
@@ -618,27 +613,6 @@ esp_err_t OtaRelay::requestGd32AppEnterBootloader()
|
||||
}
|
||||
|
||||
|
||||
ota_result_t OtaRelay::probeBootHandshake()
|
||||
{
|
||||
/* 0xB0 timeout: probe if GD32 is already in BOOT.
|
||||
* Send one lightweight HANDSHAKE_REQ, accept only echo ACK 0x00 0xAC
|
||||
* as "already in BOOT" signal; otherwise fail immediately. */
|
||||
DEBUG_INFO("OTA", "0xB0 timeout, probing if GD32 already in BOOT...");
|
||||
uint8_t payload[] = {0x00, 0xAC};
|
||||
uint8_t resp_type = 0U;
|
||||
uint8_t resp_payload[64] = {0};
|
||||
size_t resp_len = 0U;
|
||||
|
||||
esp_err_t err = SpiMaster::instance().otaTransfer(SPI_OTA_CMD_REQ, payload, sizeof(payload),
|
||||
&resp_type, resp_payload, sizeof(resp_payload), &resp_len, 500);
|
||||
if (err == ESP_OK && resp_type == SPI_OTA_RSP_ACK && isHandshakeEchoAck(resp_payload, resp_len)) {
|
||||
DEBUG_INFO("OTA", "BOOT probe success: GD32 already in BOOT, continue OTA");
|
||||
return OTA_RESULT_OK;
|
||||
}
|
||||
DEBUG_ERR("OTA", "BOOT probe failed: GD32 not in BOOT, abort (err=%d resp_type=0x%02X)", err, resp_type);
|
||||
return OTA_RESULT_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
ota_result_t OtaRelay::sendHandshakeReq()
|
||||
{
|
||||
DEBUG_INFO("OTA", "=== 阶段1: 握手开始 ===");
|
||||
@@ -1157,51 +1131,6 @@ ota_result_t OtaRelay::finishOta()
|
||||
return OTA_RESULT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 启动完整 OTA 流程的主入口
|
||||
* @return 操作结果码。
|
||||
*/
|
||||
ota_result_t OtaRelay::startHandshake()
|
||||
{
|
||||
ota_result_t res;
|
||||
|
||||
esp_err_t boot_err = requestGd32AppEnterBootloader();
|
||||
if (boot_err != ESP_OK) {
|
||||
res = probeBootHandshake();
|
||||
if (res != OTA_RESULT_OK) {
|
||||
reset();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
res = sendHandshakeReq();
|
||||
if (res != OTA_RESULT_OK) { reset(); return res; }
|
||||
|
||||
res = sendNonceAndAuthenticate();
|
||||
if (res != OTA_RESULT_OK) { reset(); return res; }
|
||||
|
||||
ota_meta_t meta;
|
||||
OtaRelay::metaLoad(&meta);
|
||||
|
||||
// 固件完整性校验
|
||||
esp_err_t verify_err = metaVerifyChecksum();
|
||||
if (verify_err != ESP_OK) {
|
||||
DEBUG_ERR("OTA", "固件完整性校验失败,中止转发");
|
||||
reset();
|
||||
return OTA_RESULT_ERR_CRC;
|
||||
}
|
||||
|
||||
res = sendFirmwareSize(meta.total_size);
|
||||
if (res != OTA_RESULT_OK) { reset(); return res; }
|
||||
|
||||
res = relayPacketsFromFlash(0);
|
||||
if (res != OTA_RESULT_OK) { reset(); return res; }
|
||||
|
||||
res = finishOta();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从 Flash 向 GD32 转发固件
|
||||
* @return 操作结果码。
|
||||
@@ -1213,8 +1142,8 @@ ota_result_t OtaRelay::forwardFirmware()
|
||||
return OTA_RESULT_ERR_STORAGE;
|
||||
}
|
||||
|
||||
DEBUG_INFO("OTA", "开始固件转发: %u 字节, %u 块",
|
||||
meta.total_size, meta.chunk_count);
|
||||
DEBUG_INFO("OTA", "开始固件转发: %u 字节",
|
||||
meta.total_size);
|
||||
|
||||
// 固件完整性校验
|
||||
{
|
||||
|
||||
@@ -16,19 +16,16 @@
|
||||
#include "esp_partition.h"
|
||||
|
||||
#define OTA_META_NVS_NAMESPACE "ota_meta"
|
||||
#define OTA_META_NVS_KEY "meta"
|
||||
|
||||
typedef struct {
|
||||
uint32_t total_size;
|
||||
uint32_t stored_size;
|
||||
uint32_t last_seq;
|
||||
uint32_t chunk_count;
|
||||
uint8_t checksum[32];
|
||||
} ota_meta_t;
|
||||
|
||||
typedef enum {
|
||||
RELAY_IDLE = 0,
|
||||
RELAY_HANDSHAKE_IDLE,
|
||||
RELAY_HANDSHAKE_SENT,
|
||||
RELAY_CHALLENGE_SENT,
|
||||
RELAY_CHALLENGE_RESPOND,
|
||||
@@ -36,13 +33,11 @@ typedef enum {
|
||||
RELAY_AUTH_COMPLETE,
|
||||
RELAY_SIZE_SENT,
|
||||
RELAY_SIZE_ACK,
|
||||
RELAY_RECEIVING,
|
||||
RELAY_RELAY_ACTIVE,
|
||||
RELAY_PACKET_SENT,
|
||||
RELAY_PACKET_ACK_OK,
|
||||
RELAY_PACKET_ACK_RETRY,
|
||||
RELAY_RECEIVE_DONE,
|
||||
RELAY_TRANSFER_DONE,
|
||||
RELAY_FINISH_SENT,
|
||||
RELAY_DONE,
|
||||
RELAY_APP_VERIFY,
|
||||
@@ -65,7 +60,6 @@ public:
|
||||
static OtaRelay& instance();
|
||||
|
||||
static void taskEntry(void *pvParameters);
|
||||
ota_result_t startHandshake();
|
||||
ota_result_t forwardFirmware();
|
||||
|
||||
/* ---- 线程安全的状态访问接口 ----
|
||||
@@ -136,7 +130,6 @@ public:
|
||||
static constexpr size_t GD32_CHALLENGE_RESPONSE_LEN = 36;
|
||||
|
||||
esp_err_t requestGd32AppEnterBootloader();
|
||||
ota_result_t probeBootHandshake();
|
||||
ota_result_t sendHandshakeReq();
|
||||
ota_result_t sendNonceAndAuthenticate();
|
||||
ota_result_t sendFirmwareSize(uint32_t size);
|
||||
@@ -157,8 +150,6 @@ public:
|
||||
static bool isConfirmPlainAck(const uint8_t *payload, size_t len);
|
||||
static bool isSizeSeq0Ack(const uint8_t *payload, size_t len);
|
||||
static bool isFinishPlainAck(const uint8_t *payload, size_t len);
|
||||
static bool isTransferDoneAck(const uint8_t *payload, size_t len);
|
||||
static bool isStructuredAckWithPayload(const uint8_t *payload, size_t len);
|
||||
|
||||
static esp_err_t pollUntilExpectedAckShape(const char *stage,
|
||||
uint8_t *resp_type,
|
||||
|
||||
+19
-6
@@ -133,14 +133,18 @@ static void ble_esp32_finish_and_reboot_task(void *pvParameters)
|
||||
// 通知前端:开始 finalize
|
||||
sendFinishEvent(BLE_OTA_FINISH_BEGIN_OTA_END, 0);
|
||||
|
||||
// 关键:reboot=false,让 finalize 真正返回、拿到 device_sha_hex,
|
||||
// 再依次推送 SHA 通知 + FINISH_DONE_OTA_END + FINISH_REBOOT_NOW,
|
||||
// 最后延迟重启。若 reboot=true,core 内部直接 esp_restart(),
|
||||
// 下面所有 notifyResponse / sendFinishEvent 都不会执行,
|
||||
// 前端也就拿不到设备端 SHA 与"收尾完成/即将重启"事件。
|
||||
char device_sha_hex[65] = {0};
|
||||
esp_err_t err = core.finalize(frontend_sha_hex,
|
||||
/*reboot=*/true,
|
||||
/*reboot=*/false,
|
||||
device_sha_hex);
|
||||
// reboot=true 时 finalize 正常不会返回(core 内部 esp_restart)
|
||||
|
||||
if (err == ESP_OK) {
|
||||
// 极端情况:reboot 未执行(理论上不会发生),仍上报并标记
|
||||
// 1) 把设备端 SHA 通过 SHA256 通知推给前端
|
||||
if (device_sha_hex[0] != '\0') {
|
||||
uint8_t sha_pkt[33] = {0};
|
||||
sha_pkt[0] = BLE_OTA_NOTIFY_SHA256;
|
||||
@@ -151,8 +155,18 @@ static void ble_esp32_finish_and_reboot_task(void *pvParameters)
|
||||
}
|
||||
BleOta::instance().notifyResponse(sha_pkt, sizeof(sha_pkt));
|
||||
}
|
||||
// 2) 等待 SHA 通知从 NimBLE host 队列送出
|
||||
vTaskDelay(pdMS_TO_TICKS(150));
|
||||
|
||||
// 3) 推送"OTA 收尾完成"与"即将重启"事件
|
||||
sendFinishEvent(BLE_OTA_FINISH_DONE_OTA_END, 0);
|
||||
sendFinishEvent(BLE_OTA_FINISH_REBOOT_NOW, 0);
|
||||
|
||||
// 4) 通知全部发出后延迟 500ms 重启
|
||||
DEBUG_INFO(TAG, "[FINISH] 通知已发送,500ms 后重启...");
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
esp_restart();
|
||||
// 不会返回
|
||||
} else if (err == ESP_ERR_INVALID_VERSION) {
|
||||
DEBUG_ERR(TAG, "[FINISH] SHA-256 不匹配,OTA 已中止");
|
||||
sendFinishEvent(BLE_OTA_FINISH_ERR_SHA_MISMATCH, 0);
|
||||
@@ -536,7 +550,6 @@ static int ble_ota_data_in_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||
meta.total_size = total_size;
|
||||
meta.stored_size = 0;
|
||||
meta.last_seq = 0;
|
||||
meta.chunk_count = (total_size + expected_payload - 1U) / expected_payload;
|
||||
|
||||
esp_err_t err = OtaRelay::metaSave(&meta);
|
||||
if (err != ESP_OK) {
|
||||
@@ -544,8 +557,8 @@ static int ble_ota_data_in_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
DEBUG_INFO(TAG, "GD32 固件存储开始: total=%" PRIu32 " chunk_count=%" PRIu32 ", payload=%zu",
|
||||
meta.total_size, meta.chunk_count, data_len);
|
||||
DEBUG_INFO(TAG, "GD32 固件存储开始: total=%" PRIu32 ", payload=%zu",
|
||||
meta.total_size, data_len);
|
||||
}
|
||||
|
||||
ota_meta_t meta = {};
|
||||
|
||||
+19
-262
@@ -21,10 +21,6 @@
|
||||
#include "esp_event.h"
|
||||
#include "esp_mac.h"
|
||||
|
||||
// SHA-256 哈希计算
|
||||
#define MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS
|
||||
#include "mbedtls/private/sha256.h"
|
||||
|
||||
#include "app_config.h"
|
||||
#include "ota_mutex.h"
|
||||
#include "wifi_ota.h"
|
||||
@@ -501,19 +497,31 @@ static esp_err_t esp32_ota_update_handler(httpd_req_t *req)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// ── 完整模式:finalize(end → 校验 → set_boot)后由 core 内部重启 ──
|
||||
// ── 完整模式:finalize 不重启,先把含设备端 SHA 的结果返回给前端 ──
|
||||
// 关键:reboot=false,让 core.finalize 真正返回,才能拿到 device_sha_hex
|
||||
// 并把响应发回前端;待响应发完后再延迟重启。
|
||||
// 若 reboot=true,core 内部直接 esp_restart(),HTTP 响应永远发不出去,
|
||||
// 前端会得到 "Failed to fetch" 而错过核对结果。
|
||||
DEBUG_INFO("OTA", "ESP32 OTA finalize, %u bytes...", (unsigned)core.getReceived());
|
||||
esp_err_t err = core.finalize(has_frontend_sha ? frontend_sha_hex : nullptr,
|
||||
/*reboot=*/true,
|
||||
/*reboot=*/false,
|
||||
device_sha_hex);
|
||||
|
||||
if (err == ESP_OK) {
|
||||
// 正常不会走到这里(reboot=true 时 core 会 esp_restart)
|
||||
char resp[256] = {0};
|
||||
// 1) 把包含设备端 SHA 的响应发回前端
|
||||
char resp[320] = {0};
|
||||
snprintf(resp, sizeof(resp),
|
||||
"{\"status\": \"ok\", \"message\": \"OTA finished\"}");
|
||||
"{\"status\": \"ok\", \"message\": \"OTA finished, rebooting\", "
|
||||
"\"sha256\": \"%s\"}",
|
||||
device_sha_hex);
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
httpd_resp_send(req, resp, strlen(resp));
|
||||
|
||||
// 2) 响应发完后延迟 500ms 重启,给 TCP 缓冲区时间 flush 到客户端
|
||||
DEBUG_INFO("OTA", "响应已发送,500ms 后重启...");
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
esp_restart();
|
||||
// 不会返回
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -552,27 +560,7 @@ static esp_err_t restart_handler(httpd_req_t *req)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HTTP GET /ota/update - 查询 ESP32 OTA 状态
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
static esp_err_t esp32_ota_status_handler(httpd_req_t *req)
|
||||
{
|
||||
http_set_cors_headers(req);
|
||||
char resp[128];
|
||||
if (Esp32OtaCore::instance().isActive()) {
|
||||
snprintf(resp, sizeof(resp),
|
||||
"{\"active\": true, \"received\": %u}",
|
||||
(unsigned int)Esp32OtaCore::instance().getReceived());
|
||||
} else {
|
||||
snprintf(resp, sizeof(resp), "{\"active\": false}");
|
||||
}
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
httpd_resp_send(req, resp, strlen(resp));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
// 从 HTTP 流中读取完整的 JSON 头(以 } 结尾)
|
||||
/**
|
||||
* @brief 返回 JSON 字符串长度,失败返回 0
|
||||
@@ -795,7 +783,6 @@ static esp_err_t ota_upload_handler(httpd_req_t *req)
|
||||
.total_size = expected_fw_size_raw,
|
||||
.stored_size = 0,
|
||||
.last_seq = 0,
|
||||
.chunk_count = (expected_fw_size_raw + OTA_BLOCK_SIZE - 1U) / OTA_BLOCK_SIZE,
|
||||
.checksum = {0}
|
||||
};
|
||||
OtaRelay::metaSave(&meta_raw);
|
||||
@@ -935,72 +922,6 @@ static esp_err_t ota_relay_trigger_handler(httpd_req_t *req)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HTTP GET /ota/status 处理器
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
static esp_err_t ota_status_handler(httpd_req_t *req)
|
||||
{
|
||||
http_set_cors_headers(req);
|
||||
DEBUG_INFO("WIFI", "=== HTTP: GET /ota/status ===");
|
||||
|
||||
ota_meta_t meta;
|
||||
OtaRelay::metaLoad(&meta);
|
||||
|
||||
char resp[256];
|
||||
int len = snprintf(resp, sizeof(resp),
|
||||
"{\"total_size\": %lu, \"stored_size\": %lu, \"last_seq\": %lu, "
|
||||
"\"storage_done\": %s, \"relay_state\": %d, \"gd32_app_alive\": %s}",
|
||||
(unsigned long)meta.total_size, (unsigned long)meta.stored_size,
|
||||
(unsigned long)meta.last_seq,
|
||||
WifiOta::instance().getGd32StorageDone() ? "true" : "false",
|
||||
OtaRelay::getState(),
|
||||
OtaRelay::getGd32AppAlive() ? "true" : "false");
|
||||
|
||||
gd32_version_t snapVer = {};
|
||||
OtaRelay::getGd32Version(&snapVer);
|
||||
DEBUG_INFO("WIFI", "OTA 状态: total=%lu, stored=%lu, done=%s, app_alive=%s",
|
||||
(unsigned long)meta.total_size, (unsigned long)meta.stored_size,
|
||||
WifiOta::instance().getGd32StorageDone() ? "true" : "false",
|
||||
OtaRelay::getGd32AppAlive() ? "true" : "false",
|
||||
snapVer.app_major, snapVer.app_minor,
|
||||
snapVer.app_patch, snapVer.app_build,
|
||||
snapVer.boot_major, snapVer.boot_minor,
|
||||
snapVer.boot_patch, snapVer.boot_build);
|
||||
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
httpd_resp_send(req, resp, len);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HTTP GET /health 处理器
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
static esp_err_t health_handler(httpd_req_t *req)
|
||||
{
|
||||
http_set_cors_headers(req);
|
||||
DEBUG_INFO("WIFI", "=== HTTP: GET /health ===");
|
||||
|
||||
health_state_t state = HealthMonitor::instance().getCurrent();
|
||||
uint32_t free_heap = esp_get_free_heap_size();
|
||||
|
||||
char resp[128];
|
||||
int len = snprintf(resp, sizeof(resp),
|
||||
"{\"health\": %d, \"free_heap\": %lu}",
|
||||
state, (unsigned long)free_heap);
|
||||
|
||||
DEBUG_INFO("WIFI", "健康状态: %d, 空闲堆: %lu", state, (unsigned long)free_heap);
|
||||
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
httpd_resp_send(req, resp, len);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HTTP GET /logs - 拉取并清空日志缓冲区
|
||||
* @param req
|
||||
@@ -1198,79 +1119,6 @@ static esp_err_t spi_send_handler(httpd_req_t *req)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HTTP GET /can/status 处理器
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
static esp_err_t can_status_handler(httpd_req_t *req)
|
||||
{
|
||||
http_set_cors_headers(req);
|
||||
char resp[128];
|
||||
snprintf(resp, sizeof(resp),
|
||||
"{\"channels\": 3, \"max_dlc\": %d, \"spi_init\": %s}",
|
||||
CAN_MAX_DLC,
|
||||
SpiMaster::instance().deviceHandle() != NULL ? "true" : "false");
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
httpd_resp_send(req, resp, strlen(resp));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HTTP GET /wifi/status 处理器
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
static esp_err_t wifi_status_handler(httpd_req_t *req)
|
||||
{
|
||||
http_set_cors_headers(req);
|
||||
char resp[256];
|
||||
char ip_str[16] = "0.0.0.0";
|
||||
int8_t rssi = -127;
|
||||
|
||||
if (WifiOta::instance().m_wifiMode == OTA_WIFI_MODE_STA && WifiOta::instance().getStaConnected()) {
|
||||
esp_netif_ip_info_t ip_info;
|
||||
esp_netif_t *sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
|
||||
if (sta_netif && esp_netif_get_ip_info(sta_netif, &ip_info) == ESP_OK) {
|
||||
snprintf(ip_str, sizeof(ip_str), IPSTR, IP2STR(&ip_info.ip));
|
||||
}
|
||||
wifi_ap_record_t ap_info;
|
||||
if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) {
|
||||
rssi = ap_info.rssi;
|
||||
}
|
||||
}
|
||||
|
||||
int len = snprintf(resp, sizeof(resp),
|
||||
"{\"mode\": \"%s\", \"ip\": \"%s\", \"rssi\": %d, \"connected\": %s}",
|
||||
WifiOta::instance().m_wifiMode == OTA_WIFI_MODE_AP ? "AP" : "STA",
|
||||
ip_str, rssi,
|
||||
(WifiOta::instance().m_wifiMode == OTA_WIFI_MODE_STA) ? (WifiOta::instance().getStaConnected() ? "true" : "false") : "N/A");
|
||||
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
httpd_resp_send(req, resp, len);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HTTP GET /api/version 处理器 - 返回固件版本、编译时间、Git hash
|
||||
*/
|
||||
static esp_err_t version_handler(httpd_req_t *req)
|
||||
{
|
||||
http_set_cors_headers(req);
|
||||
gd32_version_t gv = {}; OtaRelay::getGd32Version(&gv);
|
||||
char resp[512];
|
||||
int len = snprintf(resp, sizeof(resp),
|
||||
"{\"version\": \"%s\", \"build_time\": \"%s\", \"git_hash\": \"%s\", "
|
||||
"\"gd32_app\": \"v%d.%d.%d.%d\", \"gd32_boot\": \"v%d.%d.%d.%d\", \"gd32_alive\": %s}",
|
||||
FW_VERSION, FW_BUILD_TIME, FW_GIT_HASH,
|
||||
gv.app_major, gv.app_minor, gv.app_patch, gv.app_build,
|
||||
gv.boot_major, gv.boot_minor, gv.boot_patch, gv.boot_build,
|
||||
OtaRelay::getGd32AppAlive() ? "true" : "false");
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
httpd_resp_send(req, resp, len);
|
||||
return ESP_OK;
|
||||
}
|
||||
/**
|
||||
* @brief HTTP GET /system/status 处理器
|
||||
* @param req
|
||||
@@ -1419,21 +1267,6 @@ esp_err_t WifiOta::httpServerStart()
|
||||
};
|
||||
httpd_register_uri_handler(WifiOta::instance().m_httpServer, &relay_options_uri);
|
||||
|
||||
httpd_uri_t status_uri = {
|
||||
.uri = "/ota/status",
|
||||
.method = HTTP_GET,
|
||||
.handler = ota_status_handler,
|
||||
.user_ctx = NULL
|
||||
};
|
||||
httpd_register_uri_handler(WifiOta::instance().m_httpServer, &status_uri);
|
||||
httpd_uri_t status_options_uri = {
|
||||
.uri = "/ota/status",
|
||||
.method = HTTP_OPTIONS,
|
||||
.handler = http_options_handler,
|
||||
.user_ctx = NULL
|
||||
};
|
||||
httpd_register_uri_handler(WifiOta::instance().m_httpServer, &status_options_uri);
|
||||
|
||||
httpd_uri_t esp32_update_uri = {
|
||||
.uri = "/ota/update",
|
||||
.method = HTTP_POST,
|
||||
@@ -1464,36 +1297,6 @@ esp_err_t WifiOta::httpServerStart()
|
||||
};
|
||||
httpd_register_uri_handler(WifiOta::instance().m_httpServer, &restart_options_uri);
|
||||
|
||||
httpd_uri_t esp32_status_uri = {
|
||||
.uri = "/ota/esp32_status",
|
||||
.method = HTTP_GET,
|
||||
.handler = esp32_ota_status_handler,
|
||||
.user_ctx = NULL
|
||||
};
|
||||
httpd_register_uri_handler(WifiOta::instance().m_httpServer, &esp32_status_uri);
|
||||
httpd_uri_t esp32_status_options_uri = {
|
||||
.uri = "/ota/esp32_status",
|
||||
.method = HTTP_OPTIONS,
|
||||
.handler = http_options_handler,
|
||||
.user_ctx = NULL
|
||||
};
|
||||
httpd_register_uri_handler(WifiOta::instance().m_httpServer, &esp32_status_options_uri);
|
||||
|
||||
httpd_uri_t health_uri = {
|
||||
.uri = "/health",
|
||||
.method = HTTP_GET,
|
||||
.handler = health_handler,
|
||||
.user_ctx = NULL
|
||||
};
|
||||
httpd_register_uri_handler(WifiOta::instance().m_httpServer, &health_uri);
|
||||
httpd_uri_t health_options_uri = {
|
||||
.uri = "/health",
|
||||
.method = HTTP_OPTIONS,
|
||||
.handler = http_options_handler,
|
||||
.user_ctx = NULL
|
||||
};
|
||||
httpd_register_uri_handler(WifiOta::instance().m_httpServer, &health_options_uri);
|
||||
|
||||
httpd_uri_t logs_uri = {
|
||||
.uri = "/logs",
|
||||
.method = HTTP_GET,
|
||||
@@ -1509,21 +1312,6 @@ esp_err_t WifiOta::httpServerStart()
|
||||
};
|
||||
httpd_register_uri_handler(WifiOta::instance().m_httpServer, &logs_options_uri);
|
||||
|
||||
httpd_uri_t wifi_status_uri = {
|
||||
.uri = "/wifi/status",
|
||||
.method = HTTP_GET,
|
||||
.handler = wifi_status_handler,
|
||||
.user_ctx = NULL
|
||||
};
|
||||
httpd_register_uri_handler(WifiOta::instance().m_httpServer, &wifi_status_uri);
|
||||
httpd_uri_t wifi_status_options_uri = {
|
||||
.uri = "/wifi/status",
|
||||
.method = HTTP_OPTIONS,
|
||||
.handler = http_options_handler,
|
||||
.user_ctx = NULL
|
||||
};
|
||||
httpd_register_uri_handler(WifiOta::instance().m_httpServer, &wifi_status_options_uri);
|
||||
|
||||
httpd_uri_t system_status_uri = {
|
||||
.uri = "/system/status",
|
||||
.method = HTTP_GET,
|
||||
@@ -1555,22 +1343,6 @@ esp_err_t WifiOta::httpServerStart()
|
||||
};
|
||||
httpd_register_uri_handler(WifiOta::instance().m_httpServer, &can_send_options_uri);
|
||||
|
||||
httpd_uri_t can_status_uri = {
|
||||
.uri = "/can/status",
|
||||
.method = HTTP_GET,
|
||||
.handler = can_status_handler,
|
||||
.user_ctx = NULL
|
||||
};
|
||||
httpd_register_uri_handler(WifiOta::instance().m_httpServer, &can_status_uri);
|
||||
httpd_uri_t can_status_options_uri = {
|
||||
.uri = "/can/status",
|
||||
.method = HTTP_OPTIONS,
|
||||
.handler = http_options_handler,
|
||||
.user_ctx = NULL
|
||||
};
|
||||
httpd_register_uri_handler(WifiOta::instance().m_httpServer, &can_status_options_uri);
|
||||
|
||||
DEBUG_INFO("WIFI", "HTTP 服务器已启动");
|
||||
// SPI 直接发送
|
||||
httpd_uri_t spi_send_uri = {
|
||||
.uri = "/spi/send",
|
||||
@@ -1586,23 +1358,8 @@ esp_err_t WifiOta::httpServerStart()
|
||||
.user_ctx = NULL
|
||||
};
|
||||
httpd_register_uri_handler(WifiOta::instance().m_httpServer, &spi_send_options_uri);
|
||||
// 版本信息端点
|
||||
httpd_uri_t version_uri = {
|
||||
.uri = "/api/version",
|
||||
.method = HTTP_GET,
|
||||
.handler = version_handler,
|
||||
.user_ctx = NULL
|
||||
};
|
||||
httpd_register_uri_handler(WifiOta::instance().m_httpServer, &version_uri);
|
||||
httpd_uri_t version_options_uri = {
|
||||
.uri = "/api/version",
|
||||
.method = HTTP_OPTIONS,
|
||||
.handler = http_options_handler,
|
||||
.user_ctx = NULL
|
||||
};
|
||||
httpd_register_uri_handler(WifiOta::instance().m_httpServer, &version_options_uri);
|
||||
|
||||
DEBUG_INFO("WIFI", "注册端点: /ota/upload, /ota/relay, /ota/update, /ota/status, /ota/esp32_status, /health, /wifi/status, /system/status, /can/send, /can/status, /spi/send, /api/version");
|
||||
DEBUG_INFO("WIFI", "注册端点: /ota/upload, /ota/relay, /ota/update, /restart, /logs, /system/status, /can/send, /spi/send");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
+4
-261
@@ -5,7 +5,9 @@
|
||||
*
|
||||
* 加密实现使用 ESP32-C3 硬件 AES 加速器(通过 mbedtls port)
|
||||
*
|
||||
* 所有功能封装为 Protocol 类的静态方法。
|
||||
* 当前保留的接口:init、scrambleGenerate(nonce 生成)、
|
||||
* sessionKeyInit / sessionKeyClear(会话密钥生命周期管理)。
|
||||
* 帧构建、AES-CBC 加解密、CRC16 等中间件代码已移除。
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
@@ -29,225 +31,12 @@ void Protocol::init()
|
||||
if (m_initialized) return;
|
||||
|
||||
DEBUG_INFO("PROT", "=== 初始化协议层 ===");
|
||||
DEBUG_INFO("PROT", "协议层功能: CRC16 Modbus + 硬件 AES-128-CBC");
|
||||
DEBUG_INFO("PROT", "协议层功能: nonce 扰码 + 会话密钥管理");
|
||||
|
||||
m_initialized = true;
|
||||
DEBUG_INFO("PROT", "协议层就绪");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CRC16 Modbus(LE,低字节在前)
|
||||
*/
|
||||
uint16_t Protocol::crc16Modbus(const uint8_t *data, size_t len)
|
||||
{
|
||||
uint16_t crc = 0xFFFF;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
crc ^= data[i];
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (crc & 0x0001) {
|
||||
crc = (crc >> 1) ^ 0xA001;
|
||||
} else {
|
||||
crc >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (crc >> 8) | (crc << 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 构建 SPI 帧: SOF + CMD + LEN(2LE) + PAYLOAD + CRC16(2LE)
|
||||
*/
|
||||
int Protocol::buildFrame(uint8_t cmd, const uint8_t *payload, size_t len, uint8_t *out_frame)
|
||||
{
|
||||
if (len > FRAME_MAX_PAYLOAD) {
|
||||
DEBUG_ERR("PROT", "Payload 太大: %zu > %d", len, FRAME_MAX_PAYLOAD);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t idx = 0;
|
||||
out_frame[idx++] = FRAME_SOF;
|
||||
out_frame[idx++] = cmd;
|
||||
out_frame[idx++] = (uint8_t)(len & 0xFF);
|
||||
out_frame[idx++] = (uint8_t)((len >> 8) & 0xFF);
|
||||
|
||||
if (payload && len > 0) {
|
||||
memcpy(&out_frame[idx], payload, len);
|
||||
idx += len;
|
||||
}
|
||||
|
||||
uint16_t crc = crc16Modbus(out_frame, idx);
|
||||
out_frame[idx++] = (uint8_t)(crc & 0xFF);
|
||||
out_frame[idx++] = (uint8_t)((crc >> 8) & 0xFF);
|
||||
|
||||
DEBUG_DBG("PROT", "帧构建: cmd=0x%02X, len=%zu, crc=0x%04X", cmd, len, crc);
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 解析并校验一帧 SPI 协议数据。
|
||||
*/
|
||||
int Protocol::parseFrame(const uint8_t *frame, size_t frame_len,
|
||||
uint8_t *out_cmd, uint8_t *out_payload, size_t *out_len)
|
||||
{
|
||||
if (frame_len < 6) {
|
||||
DEBUG_WARN("PROT", "帧太短: %zu < 6", frame_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t idx = 0;
|
||||
|
||||
if (frame[idx++] != FRAME_SOF) {
|
||||
DEBUG_WARN("PROT", "无效 SOF: 0x%02X (期望 0x%02X)", frame[0], FRAME_SOF);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t cmd = frame[idx++];
|
||||
|
||||
size_t payload_len = frame[idx] | (frame[idx + 1] << 8);
|
||||
idx += 2;
|
||||
|
||||
if (payload_len > FRAME_MAX_PAYLOAD) {
|
||||
DEBUG_ERR("PROT", "Payload 长度太大: %zu > %d", payload_len, FRAME_MAX_PAYLOAD);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t expected_len = 1 + 1 + 2 + payload_len + 2;
|
||||
if (frame_len < expected_len) {
|
||||
DEBUG_WARN("PROT", "帧太短: %zu < %zu (期望)", frame_len, expected_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t received_crc = frame[idx + payload_len] | (frame[idx + payload_len + 1] << 8);
|
||||
uint16_t calc_crc = crc16Modbus(frame, idx + payload_len);
|
||||
|
||||
if (received_crc != calc_crc) {
|
||||
DEBUG_WARN("PROT", "CRC 不匹配: 收到=0x%04X, 计算=0x%04X", received_crc, calc_crc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG_DBG("PROT", "帧解析: cmd=0x%02X, len=%zu, crc=0x%04X OK", cmd, payload_len, calc_crc);
|
||||
|
||||
if (out_payload && out_len) {
|
||||
memcpy(out_payload, &frame[idx], payload_len);
|
||||
*out_len = payload_len;
|
||||
}
|
||||
if (out_cmd) {
|
||||
*out_cmd = cmd;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 使用 AES-128 CBC 对明文进行加密(PKCS#7 填充)。
|
||||
*/
|
||||
int Protocol::aesEncrypt(const uint8_t *plaintext, size_t len,
|
||||
const uint8_t *key, const uint8_t *iv,
|
||||
uint8_t *ciphertext_out)
|
||||
{
|
||||
if (!plaintext || !key || !iv || !ciphertext_out) {
|
||||
DEBUG_ERR("PROT", "AES 加密参数无效");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// PKCS#7 填充
|
||||
size_t padded_len = ((len / 16) + 1) * 16;
|
||||
uint8_t padded[FRAME_MAX_PAYLOAD + 16];
|
||||
if (padded_len > sizeof(padded)) {
|
||||
DEBUG_ERR("PROT", "填充后长度超出缓冲区: %zu", padded_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(padded, plaintext, len);
|
||||
uint8_t pad_val = (uint8_t)(padded_len - len);
|
||||
memset(&padded[len], pad_val, pad_val);
|
||||
|
||||
DEBUG_DBG("PROT", "AES 加密: 明文=%zu 字节, 填充后=%zu 字节", len, padded_len);
|
||||
|
||||
// 硬件 AES-CBC 加密(使用 ESP32-C3 硬件 AES 加速器)
|
||||
esp_aes_context aes_ctx;
|
||||
esp_aes_init(&aes_ctx);
|
||||
|
||||
int ret = esp_aes_setkey(&aes_ctx, key, 128);
|
||||
if (ret != 0) {
|
||||
DEBUG_ERR("PROT", "esp_aes_setkey 失败: %d", ret);
|
||||
esp_aes_free(&aes_ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t iv_copy[16];
|
||||
memcpy(iv_copy, iv, 16);
|
||||
|
||||
ret = esp_aes_crypt_cbc(&aes_ctx, ESP_AES_ENCRYPT, padded_len, iv_copy, padded, ciphertext_out);
|
||||
|
||||
esp_aes_free(&aes_ctx);
|
||||
|
||||
if (ret != 0) {
|
||||
DEBUG_ERR("PROT", "esp_aes_crypt_cbc 加密失败: %d", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG_DBG("PROT", "AES 加密成功: %zu -> %zu 字节", len, padded_len);
|
||||
|
||||
return padded_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 使用 AES-128 CBC 对密文进行解密(去除 PKCS#7 填充)。
|
||||
*/
|
||||
int Protocol::aesDecrypt(const uint8_t *ciphertext, size_t len,
|
||||
const uint8_t *key, const uint8_t *iv,
|
||||
uint8_t *plaintext_out)
|
||||
{
|
||||
if (!ciphertext || !key || !iv || !plaintext_out) {
|
||||
DEBUG_ERR("PROT", "AES 解密参数无效");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len % 16 != 0 || len == 0) {
|
||||
DEBUG_ERR("PROT", "Ciphertext 长度无效: %zu (必须为 16 的倍数)", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG_DBG("PROT", "AES 解密: 密文=%zu 字节", len);
|
||||
|
||||
// 硬件 AES-CBC 解密(使用 ESP32-C3 硬件 AES 加速器)
|
||||
esp_aes_context aes_ctx;
|
||||
esp_aes_init(&aes_ctx);
|
||||
|
||||
int ret = esp_aes_setkey(&aes_ctx, key, 128);
|
||||
if (ret != 0) {
|
||||
DEBUG_ERR("PROT", "esp_aes_setkey 失败: %d", ret);
|
||||
esp_aes_free(&aes_ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t iv_copy[16];
|
||||
memcpy(iv_copy, iv, 16);
|
||||
|
||||
ret = esp_aes_crypt_cbc(&aes_ctx, ESP_AES_DECRYPT, len, iv_copy, ciphertext, plaintext_out);
|
||||
|
||||
esp_aes_free(&aes_ctx);
|
||||
|
||||
if (ret != 0) {
|
||||
DEBUG_ERR("PROT", "esp_aes_crypt_cbc 解密失败: %d", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 移除 PKCS#7 填充
|
||||
uint8_t pad = plaintext_out[len - 1];
|
||||
if (pad > 16) {
|
||||
DEBUG_ERR("PROT", "无效填充: %d", pad);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t orig_len = len - pad;
|
||||
DEBUG_DBG("PROT", "AES 解密成功: %zu -> %zu 字节 (填充=%d)", len, orig_len, pad);
|
||||
|
||||
return orig_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据时间戳、地址和随机种子生成 16 字节 nonce。
|
||||
*/
|
||||
@@ -303,50 +92,4 @@ void Protocol::sessionKeyClear(session_ctx_t *sess)
|
||||
memset(sess->iv, 0, 16);
|
||||
sess->used = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 使用会话上下文加密数据。
|
||||
*/
|
||||
int Protocol::sessionEncrypt(session_ctx_t *sess, const uint8_t *in, size_t len, uint8_t *out)
|
||||
{
|
||||
if (!sess || !in || !out) return -1;
|
||||
|
||||
uint8_t iv_copy[16];
|
||||
memcpy(iv_copy, sess->iv, 16);
|
||||
|
||||
int ret = aesEncrypt(in, len, sess->key, iv_copy, out);
|
||||
|
||||
if (ret > 0) {
|
||||
memcpy(sess->iv, &out[ret - 16], 16);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 使用会话上下文解密数据。
|
||||
*/
|
||||
int Protocol::sessionDecrypt(session_ctx_t *sess, const uint8_t *in, size_t len, uint8_t *out)
|
||||
{
|
||||
if (!sess || !in || !out) return -1;
|
||||
|
||||
uint8_t iv_copy[16];
|
||||
memcpy(iv_copy, sess->iv, 16);
|
||||
|
||||
int ret = aesDecrypt(in, len, sess->key, iv_copy, out);
|
||||
|
||||
if (ret > 0) {
|
||||
memcpy(sess->iv, &in[len - 16], 16);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 使用 ESP-IDF 硬件 RNG 生成随机数
|
||||
*/
|
||||
void Protocol::generateRandomNonce(uint8_t *nonce, size_t len)
|
||||
{
|
||||
esp_fill_random(nonce, len);
|
||||
}
|
||||
@@ -17,28 +17,6 @@
|
||||
#define FRAME_MAX_PAYLOAD (64) // 安全最大 payload
|
||||
#define FRAME_OVERHEAD (6) // SOF + CMD + LEN(2) + CRC16(2)
|
||||
|
||||
// 命令码(对应 GD32 OTA 协议)
|
||||
#define CMD_HANDSHAKE_REQ (0xF0) // 握手请求
|
||||
#define CMD_CHALLENGE (0xF1) // 挑战/随机数
|
||||
#define CMD_SESSION_KEY (0xF2) // 会话密钥
|
||||
#define CMD_SEND_SIZE (0xF3) // 发送固件大小
|
||||
#define CMD_DATA_PACKET (0xF4) // 数据包
|
||||
#define CMD_DATA_END (0xF5) // 数据结束
|
||||
#define CMD_TRANSFER_DONE (0xF6) // 传输完成
|
||||
#define CMD_FINISH_OTA (0xF7) // 结束 OTA
|
||||
#define CMD_ACK (0x80) // 通用 ACK
|
||||
#define CMD_ERROR (0x81) // 通用错误
|
||||
|
||||
// ACK 状态码
|
||||
#define ACK_OK (0x00) // 成功
|
||||
#define ACK_UNSUPPORTED (0x01) // 命令不支持
|
||||
#define ACK_AUTH_FAILED (0x02) // 认证失败
|
||||
#define ACK_SIZE_OOR (0x03) // 大小超出范围
|
||||
#define ACK_CRC_FAILED (0x04) // CRC 校验失败
|
||||
#define ACK_RETRY_EXCEED (0x05) // 重试次数超限
|
||||
#define ACK_SESSION_INVALID (0x06) // 会话密钥无效
|
||||
#define ACK_FLASH_FAILED (0x07) // Flash 写入失败
|
||||
|
||||
// 安全常量(定义在 app_config.h 中)
|
||||
inline constexpr size_t MASTER_KEY_HERE_LEN = 16;
|
||||
inline constexpr size_t SCRAMBLE_CONST_HERE_LEN = 16;
|
||||
@@ -63,23 +41,10 @@ public:
|
||||
|
||||
void init();
|
||||
|
||||
static uint16_t crc16Modbus(const uint8_t *data, size_t len);
|
||||
static int buildFrame(uint8_t cmd, const uint8_t *payload, size_t len, uint8_t *out_frame);
|
||||
static int parseFrame(const uint8_t *frame, size_t frame_len,
|
||||
uint8_t *out_cmd, uint8_t *out_payload, size_t *out_len);
|
||||
static int aesEncrypt(const uint8_t *plaintext, size_t len,
|
||||
const uint8_t *key, const uint8_t *iv,
|
||||
uint8_t *ciphertext_out);
|
||||
static int aesDecrypt(const uint8_t *ciphertext, size_t len,
|
||||
const uint8_t *key, const uint8_t *iv,
|
||||
uint8_t *plaintext_out);
|
||||
static void scrambleGenerate(uint32_t timestamp, uint32_t mem_addr,
|
||||
uint32_t rand_seed, uint8_t *nonce_out);
|
||||
static int sessionKeyInit(session_ctx_t *sess, const uint8_t *k_session);
|
||||
static void sessionKeyClear(session_ctx_t *sess);
|
||||
static int sessionEncrypt(session_ctx_t *sess, const uint8_t *in, size_t len, uint8_t *out);
|
||||
static int sessionDecrypt(session_ctx_t *sess, const uint8_t *in, size_t len, uint8_t *out);
|
||||
static void generateRandomNonce(uint8_t *nonce, size_t len);
|
||||
|
||||
private:
|
||||
Protocol() = default;
|
||||
|
||||
Reference in New Issue
Block a user