feat(main): 将全局函数重构为单例类模式
- 将 debug_log 模块重构为 DebugLog 单例类,封装 UART、UDP 和环形缓冲区日志输出 - 将 health_monitor 模块重构为 HealthMonitor 单例类,统一健康状态管理和监控逻辑 - 更新 main.cpp 中的初始化调用,使用单例实例替代原有全局函数 - 添加健康监控任务作为第四个 FreeRTOS 任务,增强系统监控能力 - 更新固件版本从 0.2.11 到 0.3.0,反映架构重大变更
This commit is contained in:
+85
-94
@@ -1,6 +1,8 @@
|
||||
/*
|
||||
/*
|
||||
* spi_master.h - SPI Master 驱动头文件
|
||||
* CANFD 3通道发送接口 + 底层 SPI 总线
|
||||
*
|
||||
* SpiMaster 类封装 SPI 总线初始化、CANFD 通信和 SPI OTA 协议。
|
||||
*/
|
||||
#ifndef SPI_MASTER_H
|
||||
#define SPI_MASTER_H
|
||||
@@ -26,9 +28,6 @@
|
||||
#define SPI_OTA_RSP_WAIT (0x81)
|
||||
#define SPI_OTA_RSP_ERROR (0x82)
|
||||
|
||||
// SPI 设备句柄(外部引用)
|
||||
extern spi_device_handle_t g_spi_device;
|
||||
|
||||
// ============================================================
|
||||
// CANFD 帧格式(3通道)
|
||||
// [通道编号: 1B] [扩展帧ID: 4B BE] [数据: 1~64B]
|
||||
@@ -55,104 +54,96 @@ typedef struct {
|
||||
} can_frame_t;
|
||||
|
||||
/**
|
||||
* @brief 发送一帧 CANFD 数据,可选等待并读取响应内容。
|
||||
* @param channel CAN 通道(0~2)。
|
||||
* @param ext_id 29 位扩展帧 ID。
|
||||
* @param data 数据负载指针。
|
||||
* @param dlc 数据长度,范围 1~64。
|
||||
* @param recv_buf 接收缓冲区,可为 NULL。
|
||||
* @param recv_max 期望最大接收字节数。
|
||||
* @param timeout_ms 超时时间(毫秒)。
|
||||
* @return >= 0 接收字节数,< 0 失败。
|
||||
* @brief SPI Master 驱动类(单例)
|
||||
*
|
||||
* 封装 SPI 总线初始化、同步传输、CANFD 通信和 SPI OTA 协议。
|
||||
*/
|
||||
int gd32_can_send(can_channel_t channel, uint32_t ext_id,
|
||||
const uint8_t *data, uint8_t dlc,
|
||||
uint8_t *recv_buf, uint8_t recv_max,
|
||||
uint32_t timeout_ms);
|
||||
class SpiMaster {
|
||||
public:
|
||||
static SpiMaster& instance();
|
||||
|
||||
/**
|
||||
* @brief 发送一帧无需响应的 CANFD 数据,适合广播或通知场景。
|
||||
* @param channel CAN 通道(0~2)。
|
||||
* @param ext_id 29 位扩展帧 ID。
|
||||
* @param data 数据负载指针。
|
||||
* @param dlc 数据长度,范围 1~64。
|
||||
* @return >= 0 成功,< 0 失败。
|
||||
*/
|
||||
int gd32_can_send_no_reply(can_channel_t channel, uint32_t ext_id,
|
||||
const uint8_t *data, uint8_t dlc);
|
||||
/** @brief 初始化 SPI2 总线与目标从设备。 */
|
||||
esp_err_t init();
|
||||
|
||||
/**
|
||||
* @brief 初始化 SPI2 总线与目标从设备。
|
||||
* @return ESP_OK 成功,其他失败。
|
||||
*/
|
||||
esp_err_t spi_master_init(void);
|
||||
// ============================================================
|
||||
// 底层 SPI 传输
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* @brief 执行一次同步 SPI 事务,先发送请求,再读取请求之后的响应字节。
|
||||
* @param cmd SPI 命令码;为 0 时不额外插入命令字节。
|
||||
* @param payload 发送数据指针。
|
||||
* @param payload_len 发送数据长度。
|
||||
* @param recv_buf 接收缓冲区,可为 NULL。
|
||||
* @param recv_len 期望接收的响应长度。
|
||||
* @param timeout_ms 超时时间(毫秒)。
|
||||
* @return ESP_OK 成功,其他失败。
|
||||
*/
|
||||
esp_err_t spi_sync_transfer(uint8_t cmd, const uint8_t *payload,
|
||||
size_t payload_len, uint8_t *recv_buf,
|
||||
size_t recv_len, uint32_t timeout_ms);
|
||||
/** @brief 执行一次同步 SPI 事务,先发送请求,再读取响应字节。 */
|
||||
esp_err_t syncTransfer(uint8_t cmd, const uint8_t *payload,
|
||||
size_t payload_len, uint8_t *recv_buf,
|
||||
size_t recv_len, uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief 仅发送 SPI 请求数据,不关心返回内容。
|
||||
* @param cmd SPI 命令码;为 0 时仅发送 payload。
|
||||
* @param payload 发送数据指针。
|
||||
* @param len 发送数据长度。
|
||||
* @return ESP_OK 成功,其他失败。
|
||||
*/
|
||||
esp_err_t spi_send(uint8_t cmd, const uint8_t *payload, size_t len);
|
||||
/** @brief 仅发送 SPI 请求数据,不关心返回内容。 */
|
||||
esp_err_t send(uint8_t cmd, const uint8_t *payload, size_t len);
|
||||
|
||||
/**
|
||||
* @brief 仅接收 SPI 数据,必要时先发送命令字节,再发送哑数据产生时钟。
|
||||
* @param cmd SPI 命令码;为 0 时只发送哑数据。
|
||||
* @param recv_buf 接收缓冲区。
|
||||
* @param len 接收长度。
|
||||
* @param timeout_ms 超时时间(毫秒)。
|
||||
* @return ESP_OK 成功,其他失败。
|
||||
*/
|
||||
esp_err_t spi_recv(uint8_t cmd, uint8_t *recv_buf, size_t len, uint32_t timeout_ms);
|
||||
/** @brief 仅接收 SPI 数据,必要时先发送命令字节。 */
|
||||
esp_err_t recv(uint8_t cmd, uint8_t *recv_buf, size_t len, uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief 按 GD32 SPI OTA 最小协议执行一次请求事务 + 一次响应读取事务。
|
||||
* @param type 请求帧类型(REQ/DATA/CANCEL)。
|
||||
* @param payload 请求负载。
|
||||
* @param payload_len 负载长度。
|
||||
* @param resp_type 输出响应类型(ACK/WAIT/ERROR)。
|
||||
* @param resp_payload 输出响应负载缓冲区。
|
||||
* @param resp_max 输出响应负载最大长度。
|
||||
* @param resp_len 输出实际响应负载长度。
|
||||
* @param timeout_ms 超时。
|
||||
*/
|
||||
esp_err_t spi_ota_transfer(uint8_t type, const uint8_t *payload, size_t payload_len,
|
||||
uint8_t *resp_type, uint8_t *resp_payload,
|
||||
size_t resp_max, size_t *resp_len, uint32_t timeout_ms);
|
||||
// ============================================================
|
||||
// SPI OTA 协议
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* @brief 仅执行 SPI OTA 响应读取事务,不重复发送请求帧。
|
||||
*/
|
||||
esp_err_t spi_ota_poll_response(uint8_t *resp_type, uint8_t *resp_payload,
|
||||
size_t resp_max, size_t *resp_len, uint32_t timeout_ms);
|
||||
/** @brief 按 GD32 SPI OTA 最小协议执行一次请求 + 响应读取。 */
|
||||
esp_err_t otaTransfer(uint8_t type, const uint8_t *payload, size_t payload_len,
|
||||
uint8_t *resp_type, uint8_t *resp_payload,
|
||||
size_t resp_max, size_t *resp_len, uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief 通知正在运行的 GD32 DCU_APP 设置 OTA 标志并软复位进入 Bootloader。
|
||||
* @return ESP_OK 表示 APP 已确认;ESP_ERR_TIMEOUT 常表示 GD32 已在 Bootloader 或通信未就绪。
|
||||
*/
|
||||
esp_err_t gd32_app_request_bootloader(uint32_t timeout_ms);
|
||||
/** @brief 仅执行 SPI OTA 响应读取事务,不重复发送请求帧。 */
|
||||
esp_err_t otaPollResponse(uint8_t *resp_type, uint8_t *resp_payload,
|
||||
size_t resp_max, size_t *resp_len, uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief 向 GD32 APP 发送存活探测命令 (TYPE=0xA1),等待 APP 回复 ALIVE ACK。
|
||||
* @param timeout_ms 超时时间(毫秒)。
|
||||
* @param uptime_sec 输出 APP 运行秒数,可为 NULL。
|
||||
* @return ESP_OK APP 存活并回复;ESP_ERR_TIMEOUT 超时无响应。
|
||||
*/
|
||||
esp_err_t gd32_app_ping(uint32_t timeout_ms, uint32_t *uptime_sec);
|
||||
/** @brief 通知 GD32 DCU_APP 设置 OTA 标志并软复位进入 Bootloader。 */
|
||||
esp_err_t appRequestBootloader(uint32_t timeout_ms);
|
||||
|
||||
#endif // SPI_MASTER_H
|
||||
/** @brief 向 GD32 APP 发送存活探测命令,等待 APP 回复 ALIVE ACK。 */
|
||||
esp_err_t appPing(uint32_t timeout_ms, uint32_t *uptime_sec);
|
||||
|
||||
/** @brief 执行带重试的 SPI 同步传输。 */
|
||||
esp_err_t transferWithRetry(uint8_t cmd, const uint8_t *payload,
|
||||
size_t payload_len, uint8_t *recv_buf,
|
||||
size_t recv_len, int max_retries);
|
||||
|
||||
// ============================================================
|
||||
// CANFD 接口
|
||||
// ============================================================
|
||||
|
||||
/** @brief 发送一帧 CANFD 数据,可选等待并读取响应内容。 */
|
||||
int canSend(can_channel_t channel, uint32_t ext_id,
|
||||
const uint8_t *data, uint8_t dlc,
|
||||
uint8_t *recv_buf, uint8_t recv_max,
|
||||
uint32_t timeout_ms);
|
||||
|
||||
/** @brief 发送一帧无需响应的 CANFD 数据。 */
|
||||
int canSendNoReply(can_channel_t channel, uint32_t ext_id,
|
||||
const uint8_t *data, uint8_t dlc);
|
||||
|
||||
/** @brief 获取 SPI 设备句柄(供外部状态查询)。 */
|
||||
spi_device_handle_t deviceHandle() const { return m_spiDevice; }
|
||||
|
||||
private:
|
||||
SpiMaster() = default;
|
||||
~SpiMaster() = default;
|
||||
SpiMaster(const SpiMaster&) = delete;
|
||||
SpiMaster& operator=(const SpiMaster&) = delete;
|
||||
|
||||
spi_device_handle_t m_spiDevice = NULL;
|
||||
|
||||
// 内部 SPI 传输
|
||||
esp_err_t transferClocked(const uint8_t *tx_buf, size_t tx_len,
|
||||
uint8_t *rx_buf, size_t rx_len);
|
||||
esp_err_t transferRequestResponse(uint8_t cmd, const uint8_t *payload, size_t payload_len,
|
||||
uint8_t *rx_buf, size_t rx_len);
|
||||
|
||||
// OTA 帧工具(静态,无状态)
|
||||
static uint8_t otaCrc8(const uint8_t *data, size_t len);
|
||||
static bool otaBuildFrame(uint8_t type, const uint8_t *payload, size_t payload_len,
|
||||
uint8_t *out, size_t *out_len);
|
||||
static bool otaParseFrame(const uint8_t *frame, size_t frame_len,
|
||||
uint8_t *type, const uint8_t **payload, size_t *payload_len);
|
||||
static bool otaFindFrame(const uint8_t *buf, size_t buf_len,
|
||||
uint8_t *type, const uint8_t **payload, size_t *payload_len,
|
||||
size_t *frame_offset);
|
||||
};
|
||||
|
||||
#endif // SPI_MASTER_H
|
||||
Reference in New Issue
Block a user