docs(ota_mutex): 添加函数注释说明
This commit is contained in:
@@ -36,11 +36,18 @@ QueueHandle_t OtaRelay::dispatchQueue = NULL;
|
||||
QueueHandle_t OtaRelay::resultQueue = NULL;
|
||||
SemaphoreHandle_t OtaRelay::s_stateMutex = NULL;
|
||||
|
||||
/**
|
||||
* @brief 获取OtaRelay单例引用.
|
||||
* @return OtaRelay单例引用.
|
||||
*/
|
||||
OtaRelay& OtaRelay::instance()
|
||||
{
|
||||
static OtaRelay inst;
|
||||
return inst;
|
||||
}
|
||||
/**
|
||||
* @brief 初始化状态互斥锁.
|
||||
*/
|
||||
void OtaRelay::initMutex()
|
||||
{
|
||||
if (!s_stateMutex) {
|
||||
@@ -48,30 +55,50 @@ void OtaRelay::initMutex()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取当前中继状态.
|
||||
* @return 当前中继状态.
|
||||
*/
|
||||
relay_state_t OtaRelay::getState()
|
||||
{
|
||||
StateLockGuard lock;
|
||||
return relayState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取中继当前序号.
|
||||
* @return 当前序号值.
|
||||
*/
|
||||
uint32_t OtaRelay::getRelaySeq()
|
||||
{
|
||||
StateLockGuard lock;
|
||||
return relaySeq;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取中继总包数.
|
||||
* @return 总包数.
|
||||
*/
|
||||
uint32_t OtaRelay::getRelayTotalPackets()
|
||||
{
|
||||
StateLockGuard lock;
|
||||
return relayTotalPackets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取GD32 APP存活标志位.
|
||||
* @return true 存活,false 未存活.
|
||||
*/
|
||||
bool OtaRelay::getGd32AppAlive()
|
||||
{
|
||||
StateLockGuard lock;
|
||||
return gd32AppAlive;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取GD32固件版本.
|
||||
* @param out 输出参数,版本结构体指针.
|
||||
*/
|
||||
void OtaRelay::getGd32Version(gd32_version_t *out)
|
||||
{
|
||||
if (!out) return;
|
||||
@@ -79,30 +106,50 @@ void OtaRelay::getGd32Version(gd32_version_t *out)
|
||||
*out = gd32Version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置中继状态.
|
||||
* @param s 目标状态值.
|
||||
*/
|
||||
void OtaRelay::setState(relay_state_t s)
|
||||
{
|
||||
StateLockGuard lock;
|
||||
relayState = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置中继当前序号.
|
||||
* @param seq 序号值.
|
||||
*/
|
||||
void OtaRelay::setRelaySeq(uint32_t seq)
|
||||
{
|
||||
StateLockGuard lock;
|
||||
relaySeq = seq;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置中继总包数.
|
||||
* @param total 总包数.
|
||||
*/
|
||||
void OtaRelay::setRelayTotalPackets(uint32_t total)
|
||||
{
|
||||
StateLockGuard lock;
|
||||
relayTotalPackets = total;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置GD32 APP存活标志位.
|
||||
* @param alive 存活状态.
|
||||
*/
|
||||
void OtaRelay::setGd32AppAlive(bool alive)
|
||||
{
|
||||
StateLockGuard lock;
|
||||
gd32AppAlive = alive;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置GD32固件版本.
|
||||
* @param ver 版本结构体引用.
|
||||
*/
|
||||
void OtaRelay::setGd32Version(const gd32_version_t &ver)
|
||||
{
|
||||
StateLockGuard lock;
|
||||
@@ -115,6 +162,13 @@ void OtaRelay::setGd32Version(const gd32_version_t &ver)
|
||||
// 内部工具函数
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* @brief 检查缓冲区是否全部为指定值.
|
||||
* @param buf 缓冲区指针.
|
||||
* @param len 缓冲区长度.
|
||||
* @param value 待检查的值.
|
||||
* @return true 全部为指定值,false 不是.
|
||||
*/
|
||||
static bool bytesAllValue(const uint8_t *buf, size_t len, uint8_t value)
|
||||
{
|
||||
if (!buf || len == 0) return false;
|
||||
@@ -124,6 +178,13 @@ static bool bytesAllValue(const uint8_t *buf, size_t len, uint8_t value)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 使用AES-128-ECB加密单个16字节块.
|
||||
* @param key 16字节密钥.
|
||||
* @param in 16字节输入数据.
|
||||
* @param out 16字节输出数据.
|
||||
* @return 0 成功,-1 失败.
|
||||
*/
|
||||
int OtaRelay::aes128EcbEncryptBlockLocal(const uint8_t *key, const uint8_t *in, uint8_t *out)
|
||||
{
|
||||
esp_aes_context ctx;
|
||||
@@ -134,6 +195,13 @@ int OtaRelay::aes128EcbEncryptBlockLocal(const uint8_t *key, const uint8_t *in,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 记录响应载荷日志.
|
||||
* @param stage 阶段名称字符串.
|
||||
* @param resp_type 响应类型.
|
||||
* @param payload 载荷指针.
|
||||
* @param len 载荷长度.
|
||||
*/
|
||||
void OtaRelay::logRespPayload(const char *stage, uint8_t resp_type, const uint8_t *payload, size_t len)
|
||||
{
|
||||
char hex[193] = {0};
|
||||
@@ -145,6 +213,17 @@ void OtaRelay::logRespPayload(const char *stage, uint8_t resp_type, const uint8_
|
||||
n > 0 ? hex : "<empty>", len > n ? "..." : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 循环等待直到响应不再是WAIT状态.
|
||||
* @param stage 阶段名称字符串.
|
||||
* @param resp_type 响应类型输出.
|
||||
* @param resp_payload 响应载荷缓冲区.
|
||||
* @param resp_max 缓冲区最大长度.
|
||||
* @param resp_len 实际响应长度输出.
|
||||
* @param timeout_ms 单次轮询超时毫秒.
|
||||
* @param max_wait_rounds 最大WAIT轮次.
|
||||
* @return ESP_OK 成功,其他失败.
|
||||
*/
|
||||
esp_err_t OtaRelay::waitUntilNotWait(const char *stage, uint8_t *resp_type,
|
||||
uint8_t *resp_payload, size_t resp_max,
|
||||
size_t *resp_len, uint32_t timeout_ms, uint32_t max_wait_rounds)
|
||||
@@ -162,6 +241,13 @@ esp_err_t OtaRelay::waitUntilNotWait(const char *stage, uint8_t *resp_type,
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断是否为带序号的结构化ACK.
|
||||
* @param payload 载荷指针.
|
||||
* @param len 载荷长度.
|
||||
* @param expected_seq 期望的序号.
|
||||
* @return true 匹配成功,false 不匹配.
|
||||
*/
|
||||
bool OtaRelay::isStructuredAckWithSeq(const uint8_t *payload, size_t len, uint32_t expected_seq)
|
||||
{
|
||||
if (!payload || len < 6) return false;
|
||||
@@ -171,6 +257,14 @@ bool OtaRelay::isStructuredAckWithSeq(const uint8_t *payload, size_t len, uint32
|
||||
return seq == expected_seq;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 解析结构化错误帧.
|
||||
* @param payload 载荷指针.
|
||||
* @param len 载荷长度.
|
||||
* @param seq_out 输出错误序号.
|
||||
* @param err_out 输出错误码.
|
||||
* @return true 解析成功,false 解析失败.
|
||||
*/
|
||||
bool OtaRelay::parseStructuredError(const uint8_t *payload, size_t len, uint32_t *seq_out, uint8_t *err_out)
|
||||
{
|
||||
if (!payload || len < 7) return false;
|
||||
@@ -181,18 +275,48 @@ bool OtaRelay::parseStructuredError(const uint8_t *payload, size_t len, uint32_t
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断是否为握手回显ACK.
|
||||
* @param payload 载荷指针.
|
||||
* @param len 载荷长度.
|
||||
* @return true 是握手回显ACK,false 不是.
|
||||
*/
|
||||
bool OtaRelay::isHandshakeEchoAck(const uint8_t *payload, size_t len)
|
||||
{ return payload && len >= 2U && payload[0] == 0x00U && payload[1] == 0xACU; }
|
||||
|
||||
/**
|
||||
* @brief 判断是否为挑战应答ACK.
|
||||
* @param payload 载荷指针.
|
||||
* @param len 载荷长度.
|
||||
* @return true 是挑战应答ACK,false 不是.
|
||||
*/
|
||||
bool OtaRelay::isChallengePayloadAck(const uint8_t *payload, size_t len)
|
||||
{ return payload && len == GD32_CHALLENGE_RESPONSE_LEN; }
|
||||
|
||||
/**
|
||||
* @brief 判断是否为普通确认ACK.
|
||||
* @param payload 载荷指针.
|
||||
* @param len 载荷长度.
|
||||
* @return true 是确认ACK,false 不是.
|
||||
*/
|
||||
bool OtaRelay::isConfirmPlainAck(const uint8_t *payload, size_t len)
|
||||
{ return payload && len == 2U && payload[0] == 0xBAU && payload[1] == 0xC0U; }
|
||||
|
||||
/**
|
||||
* @brief 判断是否为大小序号0的ACK.
|
||||
* @param payload 载荷指针.
|
||||
* @param len 载荷长度.
|
||||
* @return true 是大小序号0ACK,false 不是.
|
||||
*/
|
||||
bool OtaRelay::isSizeSeq0Ack(const uint8_t *payload, size_t len)
|
||||
{ return isStructuredAckWithSeq(payload, len, 0U); }
|
||||
|
||||
/**
|
||||
* @brief 判断是否为普通的结束ACK.
|
||||
* @param payload 载荷指针.
|
||||
* @param len 载荷长度.
|
||||
* @return true 是结束ACK,false 不是.
|
||||
*/
|
||||
bool OtaRelay::isFinishPlainAck(const uint8_t *payload, size_t len)
|
||||
{
|
||||
if (!payload) return false;
|
||||
@@ -201,6 +325,19 @@ bool OtaRelay::isFinishPlainAck(const uint8_t *payload, size_t len)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 轮询直到收到预期的ACK形状.
|
||||
* @param stage 阶段名称字符串.
|
||||
* @param resp_type 响应类型输出.
|
||||
* @param resp_payload 响应载荷缓冲区.
|
||||
* @param resp_max 缓冲区最大长度.
|
||||
* @param resp_len 实际响应长度输出.
|
||||
* @param poll_timeout_ms 轮询超时毫秒.
|
||||
* @param wait_rounds WAIT状态最大轮询次数.
|
||||
* @param maxExtraPolls 额外轮询次数.
|
||||
* @param matcher 匹配回调函数.
|
||||
* @return ESP_OK 成功,其他失败.
|
||||
*/
|
||||
esp_err_t OtaRelay::pollUntilExpectedAckShape(const char *stage,
|
||||
uint8_t *resp_type, uint8_t *resp_payload,
|
||||
size_t resp_max, size_t *resp_len,
|
||||
@@ -233,6 +370,14 @@ esp_err_t OtaRelay::pollUntilExpectedAckShape(const char *stage,
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 解析并验证挑战应答载荷.
|
||||
* @param resp_payload 响应载荷指针.
|
||||
* @param resp_len 响应长度.
|
||||
* @param out_k_session 输出会话密钥.
|
||||
* @param out_uid 输出GD32 UID.
|
||||
* @return true 验证通过,false 验证失败.
|
||||
*/
|
||||
bool OtaRelay::parseAndVerifyChallengePayload(const uint8_t *resp_payload, size_t resp_len,
|
||||
uint8_t *out_k_session, uint8_t *out_uid)
|
||||
{
|
||||
@@ -265,6 +410,13 @@ bool OtaRelay::parseAndVerifyChallengePayload(const uint8_t *resp_payload, size_
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 使用AES-128-ECB加密48字节数据.
|
||||
* @param key 16字节密钥.
|
||||
* @param in 48字节输入数据.
|
||||
* @param out 48字节输出数据.
|
||||
* @return true 加密成功,false 加密失败.
|
||||
*/
|
||||
bool OtaRelay::aes128EcbEncrypt48Bytes(const uint8_t *key, const uint8_t *in, uint8_t *out)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
@@ -272,6 +424,12 @@ bool OtaRelay::aes128EcbEncrypt48Bytes(const uint8_t *key, const uint8_t *in, ui
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 使用密钥计算48字节数据的CRC32.
|
||||
* @param key 16字节密钥.
|
||||
* @param data48 48字节输入数据.
|
||||
* @param output 输出4字节CRC32结果.
|
||||
*/
|
||||
void OtaRelay::calculateCrc32WithKey(const uint8_t *key, const uint8_t *data48, uint8_t *output)
|
||||
{
|
||||
uint32_t crc = 0xFFFFFFFFU;
|
||||
@@ -613,6 +771,10 @@ esp_err_t OtaRelay::requestGd32AppEnterBootloader()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 阶段1 - 发送握手请求并等待确认.
|
||||
* @return 操作结果码.
|
||||
*/
|
||||
ota_result_t OtaRelay::sendHandshakeReq()
|
||||
{
|
||||
DEBUG_INFO("OTA", "=== 阶段1: 握手开始 ===");
|
||||
|
||||
@@ -57,9 +57,21 @@ typedef enum {
|
||||
|
||||
class OtaRelay {
|
||||
public:
|
||||
/**
|
||||
* @brief 获取OtaRelay单例引用.
|
||||
* @return OtaRelay单例引用.
|
||||
*/
|
||||
static OtaRelay& instance();
|
||||
|
||||
/**
|
||||
* @brief OTA中继FreeRTOS任务入口.
|
||||
* @param pvParameters FreeRTOS任务参数.
|
||||
*/
|
||||
static void taskEntry(void *pvParameters);
|
||||
/**
|
||||
* @brief 从Flash向GD32转发固件(主流程).
|
||||
* @return 操作结果码.
|
||||
*/
|
||||
ota_result_t forwardFirmware();
|
||||
|
||||
/* ---- 线程安全的状态访问接口 ----
|
||||
@@ -67,27 +79,117 @@ public:
|
||||
* 状态机内部(OTA 任务)可直接写 static 成员,
|
||||
* 跨任务读/写必须走这些 API。
|
||||
*/
|
||||
/**
|
||||
* @brief 获取当前中继状态.
|
||||
* @return 当前中继状态.
|
||||
*/
|
||||
static relay_state_t getState();
|
||||
/**
|
||||
* @brief 获取中继当前序号.
|
||||
* @return 当前序号值.
|
||||
*/
|
||||
static uint32_t getRelaySeq();
|
||||
/**
|
||||
* @brief 获取中继总包数.
|
||||
* @return 总包数.
|
||||
*/
|
||||
static uint32_t getRelayTotalPackets();
|
||||
/**
|
||||
* @brief 获取GD32 APP存活标志位.
|
||||
* @return true 存活,false 未存活.
|
||||
*/
|
||||
static bool getGd32AppAlive();
|
||||
/**
|
||||
* @brief 获取GD32固件版本.
|
||||
* @param out 输出参数,版本结构体指针.
|
||||
*/
|
||||
static void getGd32Version(gd32_version_t *out);
|
||||
/**
|
||||
* @brief 设置中继状态.
|
||||
* @param s 目标状态值.
|
||||
*/
|
||||
static void setState(relay_state_t s);
|
||||
/**
|
||||
* @brief 设置中继当前序号.
|
||||
* @param seq 序号值.
|
||||
*/
|
||||
static void setRelaySeq(uint32_t seq);
|
||||
/**
|
||||
* @brief 设置中继总包数.
|
||||
* @param total 总包数.
|
||||
*/
|
||||
static void setRelayTotalPackets(uint32_t total);
|
||||
/**
|
||||
* @brief 设置GD32 APP存活标志位.
|
||||
* @param alive 存活状态.
|
||||
*/
|
||||
static void setGd32AppAlive(bool alive);
|
||||
/**
|
||||
* @brief 获取GD32固件版本.
|
||||
* @param ver 待设置的版本结构体引用.
|
||||
*/
|
||||
static void setGd32Version(const gd32_version_t &ver);
|
||||
|
||||
/**
|
||||
* @brief 重置状态机.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* @brief Flash写入接口(支持非4字节对齐写入).
|
||||
* @param offset 分区内写入偏移.
|
||||
* @param data 待写入的数据指针.
|
||||
* @param len 数据长度(字节).
|
||||
* @return ESP_OK 成功,其他失败.
|
||||
*/
|
||||
static esp_err_t flashWriteChunk(uint32_t offset, const uint8_t *data, size_t len);
|
||||
/**
|
||||
* @brief 从OTA缓存分区读取数据块.
|
||||
* @param offset 分区内读取偏移.
|
||||
* @param data 读取缓冲区指针.
|
||||
* @param len 读取长度(字节).
|
||||
* @return ESP_OK 成功,其他失败.
|
||||
*/
|
||||
static esp_err_t flashReadChunk(uint32_t offset, uint8_t *data, size_t len);
|
||||
/**
|
||||
* @brief 从Flash加载元数据.
|
||||
* @param meta 输出参数,加载后的元数据结构体指针.
|
||||
* @return ESP_OK 成功,其他失败.
|
||||
*/
|
||||
static esp_err_t metaLoad(ota_meta_t *meta);
|
||||
/**
|
||||
* @brief 保存元数据到Flash.
|
||||
* @param meta 待保存的元数据结构体指针.
|
||||
* @return ESP_OK 成功,其他失败.
|
||||
*/
|
||||
static esp_err_t metaSave(const ota_meta_t *meta);
|
||||
/**
|
||||
* @brief 传输过程中更新元数据.
|
||||
* @param stored_size 已存储的固件大小(字节).
|
||||
* @param last_seq 最后成功的分块序号.
|
||||
* @return ESP_OK 成功,其他失败.
|
||||
*/
|
||||
static esp_err_t metaUpdate(uint32_t stored_size, uint32_t last_seq);
|
||||
/**
|
||||
* @brief OTA完成或中止时清除元数据.
|
||||
* @return ESP_OK 成功,其他失败.
|
||||
*/
|
||||
static esp_err_t metaClear();
|
||||
/**
|
||||
* @brief 计算gd32_ota分区中已存储固件的SHA-256.
|
||||
* @param out_sha256 输出32字节SHA-256摘要.
|
||||
* @return ESP_OK 成功,其他失败.
|
||||
*/
|
||||
static esp_err_t computeFlashSha256(uint8_t out_sha256[32]);
|
||||
/**
|
||||
* @brief 固件接收完毕后计算SHA-256并写入元数据.
|
||||
* @return ESP_OK 成功,其他失败.
|
||||
*/
|
||||
static esp_err_t metaFinalizeChecksum();
|
||||
/**
|
||||
* @brief 校验固件完整性(SHA-256).
|
||||
* @return ESP_OK 校验通过,ESP_ERR_INVALID_CRC 校验失败.
|
||||
*/
|
||||
static esp_err_t metaVerifyChecksum();
|
||||
|
||||
// 公开状态(状态机内部直接访问;跨任务请用 getter/setter)
|
||||
@@ -101,17 +203,31 @@ public:
|
||||
|
||||
// 线程安全锁
|
||||
static SemaphoreHandle_t s_stateMutex;
|
||||
/**
|
||||
* @brief 初始化状态互斥锁.
|
||||
*/
|
||||
static void initMutex();
|
||||
static constexpr TickType_t kLockTimeout = pdMS_TO_TICKS(50);
|
||||
|
||||
class StateLockGuard {
|
||||
public:
|
||||
/**
|
||||
* @brief 构造时获取互斥锁.
|
||||
* @param timeout 等待超时(时钟节拍),默认50ms.
|
||||
*/
|
||||
explicit StateLockGuard(TickType_t timeout = kLockTimeout) {
|
||||
m_locked = (s_stateMutex && xSemaphoreTake(s_stateMutex, timeout) == pdTRUE);
|
||||
}
|
||||
/**
|
||||
* @brief 析构时释放互斥锁.
|
||||
*/
|
||||
~StateLockGuard() {
|
||||
if (m_locked && s_stateMutex) { xSemaphoreGive(s_stateMutex); }
|
||||
}
|
||||
/**
|
||||
* @brief 检查是否成功获取锁.
|
||||
* @return true 已锁定,false 未锁定.
|
||||
*/
|
||||
bool isLocked() const { return m_locked; }
|
||||
StateLockGuard(const StateLockGuard&) = delete;
|
||||
StateLockGuard& operator=(const StateLockGuard&) = delete;
|
||||
@@ -129,28 +245,137 @@ public:
|
||||
static constexpr size_t GD32_UID_LEN = 12;
|
||||
static constexpr size_t GD32_CHALLENGE_RESPONSE_LEN = 36;
|
||||
|
||||
/**
|
||||
* @brief 请求GD32 APP进入Bootloader.
|
||||
* @return 操作结果码.
|
||||
*/
|
||||
esp_err_t requestGd32AppEnterBootloader();
|
||||
/**
|
||||
* @brief 发送握手请求.
|
||||
* @return 操作结果码.
|
||||
*/
|
||||
ota_result_t sendHandshakeReq();
|
||||
/**
|
||||
* @brief 发送随机数并与GD32相互认证.
|
||||
* @return 操作结果码.
|
||||
*/
|
||||
ota_result_t sendNonceAndAuthenticate();
|
||||
/**
|
||||
* @brief 向GD32发送固件总大小.
|
||||
* @param size 固件总字节数.
|
||||
* @return 操作结果码.
|
||||
*/
|
||||
ota_result_t sendFirmwareSize(uint32_t size);
|
||||
/**
|
||||
* @brief 从Flash向GD32转发固件包.
|
||||
* @param deadline_tick 截止时间戳(可选),0表示无超时.
|
||||
* @return 操作结果码.
|
||||
*/
|
||||
ota_result_t relayPacketsFromFlash(TickType_t deadline_tick = 0);
|
||||
/**
|
||||
* @brief 完成OTA并发送结束指令.
|
||||
* @return 操作结果码.
|
||||
*/
|
||||
ota_result_t finishOta();
|
||||
|
||||
/**
|
||||
* @brief 使用AES-128-ECB加密单个16字节块.
|
||||
* @param key 16字节密钥.
|
||||
* @param in 16字节输入数据.
|
||||
* @param out 16字节输出数据.
|
||||
* @return 0 成功,-1 失败.
|
||||
*/
|
||||
static int aes128EcbEncryptBlockLocal(const uint8_t *key, const uint8_t *in, uint8_t *out);
|
||||
/**
|
||||
* @brief 记录响应载荷日志.
|
||||
* @param stage 阶段名称字符串.
|
||||
* @param resp_type 响应类型.
|
||||
* @param payload 载荷指针.
|
||||
* @param len 载荷长度.
|
||||
*/
|
||||
static void logRespPayload(const char *stage, uint8_t resp_type, const uint8_t *payload, size_t len);
|
||||
/**
|
||||
* @brief 循环等待直到响应不再是WAIT状态.
|
||||
* @param stage 阶段名称字符串.
|
||||
* @param resp_type 响应类型输出.
|
||||
* @param resp_payload 响应载荷缓冲区.
|
||||
* @param resp_max 缓冲区最大长度.
|
||||
* @param resp_len 实际响应长度输出.
|
||||
* @param timeout_ms 单次轮询超时毫秒.
|
||||
* @param max_wait_rounds 最大WAIT轮次.
|
||||
* @return ESP_OK 成功,其他失败.
|
||||
*/
|
||||
esp_err_t waitUntilNotWait(const char *stage, uint8_t *resp_type,
|
||||
uint8_t *resp_payload, size_t resp_max,
|
||||
size_t *resp_len, uint32_t timeout_ms,
|
||||
uint32_t max_wait_rounds);
|
||||
|
||||
/**
|
||||
* @brief 判断是否为带序号的结构化ACK.
|
||||
* @param payload 载荷指针.
|
||||
* @param len 载荷长度.
|
||||
* @param expected_seq 期望的序号.
|
||||
* @return true 匹配成功,false 不匹配.
|
||||
*/
|
||||
static bool isStructuredAckWithSeq(const uint8_t *payload, size_t len, uint32_t expected_seq);
|
||||
/**
|
||||
* @brief 解析结构化错误帧.
|
||||
* @param payload 载荷指针.
|
||||
* @param len 载荷长度.
|
||||
* @param seq_out 输出错误序号.
|
||||
* @param err_out 输出错误码.
|
||||
* @return true 解析成功,false 解析失败.
|
||||
*/
|
||||
static bool parseStructuredError(const uint8_t *payload, size_t len, uint32_t *seq_out, uint8_t *err_out);
|
||||
/**
|
||||
* @brief 判断是否为握手回显ACK.
|
||||
* @param payload 载荷指针.
|
||||
* @param len 载荷长度.
|
||||
* @return true 是握手回显ACK,false 不是.
|
||||
*/
|
||||
static bool isHandshakeEchoAck(const uint8_t *payload, size_t len);
|
||||
/**
|
||||
* @brief 判断是否为挑战应答ACK.
|
||||
* @param payload 载荷指针.
|
||||
* @param len 载荷长度.
|
||||
* @return true 是挑战应答ACK,false 不是.
|
||||
*/
|
||||
static bool isChallengePayloadAck(const uint8_t *payload, size_t len);
|
||||
/**
|
||||
* @brief 判断是否为普通确认ACK.
|
||||
* @param payload 载荷指针.
|
||||
* @param len 载荷长度.
|
||||
* @return true 是确认ACK,false 不是.
|
||||
*/
|
||||
static bool isConfirmPlainAck(const uint8_t *payload, size_t len);
|
||||
/**
|
||||
* @brief 判断是否为大小序号0的ACK.
|
||||
* @param payload 载荷指针.
|
||||
* @param len 载荷长度.
|
||||
* @return true 是大小序号0ACK,false 不是.
|
||||
*/
|
||||
static bool isSizeSeq0Ack(const uint8_t *payload, size_t len);
|
||||
/**
|
||||
* @brief 判断是否为普通的结束ACK.
|
||||
* @param payload 载荷指针.
|
||||
* @param len 载荷长度.
|
||||
* @return true 是结束ACK,false 不是.
|
||||
*/
|
||||
static bool isFinishPlainAck(const uint8_t *payload, size_t len);
|
||||
|
||||
/**
|
||||
* @brief 轮询直到收到预期的ACK形状.
|
||||
* @param stage 阶段名称字符串.
|
||||
* @param resp_type 响应类型输出.
|
||||
* @param resp_payload 响应载荷缓冲区.
|
||||
* @param resp_max 响应缓冲区最大长度.
|
||||
* @param resp_len 实际响应长度输出.
|
||||
* @param poll_timeout_ms 轮询超时毫秒.
|
||||
* @param wait_rounds WAIT状态最大轮询次数.
|
||||
* @param maxExtraPolls 额外轮询次数.
|
||||
* @param matcher 匹配回调函数.
|
||||
* @return ESP_OK 成功,其他失败.
|
||||
*/
|
||||
static esp_err_t pollUntilExpectedAckShape(const char *stage,
|
||||
uint8_t *resp_type,
|
||||
uint8_t *resp_payload,
|
||||
@@ -160,9 +385,30 @@ public:
|
||||
uint32_t wait_rounds,
|
||||
uint32_t maxExtraPolls,
|
||||
bool (*matcher)(const uint8_t *, size_t));
|
||||
/**
|
||||
* @brief 解析并验证挑战应答载荷.
|
||||
* @param resp_payload 响应载荷指针.
|
||||
* @param resp_len 响应长度.
|
||||
* @param out_k_session 输出会话密钥.
|
||||
* @param out_uid 输出GD32 UID.
|
||||
* @return true 验证通过,false 验证失败.
|
||||
*/
|
||||
static bool parseAndVerifyChallengePayload(const uint8_t *resp_payload, size_t resp_len,
|
||||
uint8_t *out_k_session, uint8_t *out_uid);
|
||||
/**
|
||||
* @brief 使用AES-128-ECB加密48字节数据.
|
||||
* @param key 16字节密钥.
|
||||
* @param in 48字节输入数据.
|
||||
* @param out 48字节输出数据.
|
||||
* @return true 加密成功,false 加密失败.
|
||||
*/
|
||||
static bool aes128EcbEncrypt48Bytes(const uint8_t *key, const uint8_t *in, uint8_t *out);
|
||||
/**
|
||||
* @brief 使用密钥计算48字节数据的CRC32.
|
||||
* @param key 16字节密钥.
|
||||
* @param data48 48字节输入数据.
|
||||
* @param output 输出4字节CRC32结果.
|
||||
*/
|
||||
static void calculateCrc32WithKey(const uint8_t *key, const uint8_t *data48, uint8_t *output);
|
||||
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user