feat(can): 添加CAN总线错误计数器和总线状态监控
添加了硬件发送错误计数器(tec)、接收错误计数器(rec)和总线状态位图(bus_state)字段, 用于更全面的CAN总线状态监控。同时新增CAN_RX_MODE_BRIDGE_0_TO_12模式,支持CAN0到 CAN1和CAN2的桥接功能。 BREAKING CHANGE: CAN反馈协议格式扩展,增加了3个字节的状态信息。
This commit is contained in:
@@ -4,11 +4,11 @@
|
||||
// 固件版本
|
||||
#define FW_VERSION_MAJOR 0
|
||||
#define FW_VERSION_MINOR 3
|
||||
#define FW_VERSION_PATCH 35
|
||||
#define FW_VERSION_STRING "0.3.35"
|
||||
#define FW_VERSION_PATCH 36
|
||||
#define FW_VERSION_STRING "0.3.36"
|
||||
|
||||
// 编译时间
|
||||
#define BUILD_TIME "2026-06-29 01:50:43"
|
||||
#define BUILD_TIME "2026-07-02 01:59:27"
|
||||
|
||||
// Git 信息
|
||||
#define GIT_HASH "a93dba6"
|
||||
#define GIT_HASH "6335d05"
|
||||
|
||||
@@ -57,19 +57,7 @@ static void taskLoop(void *)
|
||||
if (rc == 0) {
|
||||
publish(ch, fb);
|
||||
|
||||
const bool prevOk = s_prev_poll_ok[ch];
|
||||
const bool changed = (!s_prev_valid[ch]) ||
|
||||
(fb.stats.rx_count != s_prev_stats[ch].rx_count) ||
|
||||
(fb.stats.tx_count != s_prev_stats[ch].tx_count) ||
|
||||
(fb.stats.rx_drop_count != s_prev_stats[ch].rx_drop_count) ||
|
||||
(fb.stats.error_count != s_prev_stats[ch].error_count) ||
|
||||
(fb.stats.mode != s_prev_stats[ch].mode) ||
|
||||
(fb.stats.snapshot_seq != s_prev_stats[ch].snapshot_seq);
|
||||
const bool abnormal = (fb.stats.rx_drop_count != 0U) ||
|
||||
(fb.stats.error_count != 0U) ||
|
||||
(fb.stats.mode != 0U);
|
||||
|
||||
if (!prevOk || changed || abnormal) {
|
||||
if (fb.stats.error_count != 0U) {
|
||||
DEBUG_INFO(kTag,
|
||||
"CH%u seq=%lu mode=%u rx=%lu tx=%lu drop=%lu err=%lu ids=%u",
|
||||
static_cast<unsigned>(ch),
|
||||
|
||||
@@ -477,13 +477,17 @@ esp_err_t OtaCoordinator::beginEsp32OtaWithRetry(uint32_t total_size, ota_channe
|
||||
// 两通道并发写同一 OTA 分区(之前 BLE 与 WiFi 可同时 OTA 的根因)。
|
||||
// 避免连续 isIdle() + getSystemState() 各加锁一次(共 2 次锁)。
|
||||
ota_system_state_t cur = getSystemState();
|
||||
if (!isIdleState(cur)) {
|
||||
if (!isIdleState(cur) && cur != OTA_SYS_ERROR) {
|
||||
DEBUG_WARN(TAG, "ESP32 OTA 被拒绝且系统非空闲 (state=%d),不强制清理,直接失败",
|
||||
(int)cur);
|
||||
return err;
|
||||
}
|
||||
// 协调器空闲但 Esp32OtaCore.begin 仍被拒 → 锁残留,强制清理后重试
|
||||
DEBUG_WARN(TAG, "ESP32 OTA 被拒绝但系统空闲,判定为锁残留,强制清理状态机后重试");
|
||||
|
||||
if (cur == OTA_SYS_ERROR) {
|
||||
DEBUG_WARN(TAG, "ESP32 OTA 被拒绝但协调器处于 ERROR,清理底层残留句柄后重试");
|
||||
} else {
|
||||
DEBUG_WARN(TAG, "ESP32 OTA 被拒绝但系统空闲,判定为锁残留,强制清理状态机后重试");
|
||||
}
|
||||
Esp32OtaCore::instance().forceCleanup();
|
||||
err = beginEsp32Ota(total_size, channel);
|
||||
}
|
||||
@@ -738,6 +742,7 @@ OtaSnapshot OtaCoordinator::getSnapshot() const
|
||||
bool h = lock();
|
||||
if (h) {
|
||||
snap.sys_state = m_sysState;
|
||||
snap.channel = m_otaChannel;
|
||||
snap.storage_done = m_gd32StorageDone;
|
||||
// 就地把状态枚举转字符串,与 sys_state 来自同一时刻
|
||||
snap.sys_state_str = stateToString(snap.sys_state);
|
||||
|
||||
@@ -57,6 +57,7 @@ typedef enum {
|
||||
struct OtaSnapshot {
|
||||
ota_system_state_t sys_state = OTA_SYS_IDLE; ///< 系统级 OTA 状态
|
||||
const char *sys_state_str = "IDLE"; ///< 状态字符串
|
||||
ota_channel_t channel = OTA_CHANNEL_WIFI; ///< 当前/最近一次 OTA 通道
|
||||
bool storage_done = false; ///< GD32 固件存储完成标志
|
||||
ota_meta_t meta = {}; ///< GD32 NVS 元数据
|
||||
RelaySnapshot relay; ///< 中继进度快照
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* http_handlers.cpp - HTTP 请求处理器实现
|
||||
* 从 wifi_ota.cpp 提取的 HTTP handler 函数
|
||||
*/
|
||||
@@ -746,13 +746,17 @@ esp_err_t can_feedback_handler(httpd_req_t *req)
|
||||
if (valid[i]) {
|
||||
p += sprintf(p,
|
||||
",\"mode\":%u,\"seq\":%lu,\"rx\":%lu,\"tx\":%lu,"
|
||||
"\"drop\":%lu,\"err\":%lu,\"count\":%u,\"entries\":[",
|
||||
"\"drop\":%lu,\"err\":%lu,\"tec\":%u,\"rec\":%u,"
|
||||
"\"bus_state\":%u,\"count\":%u,\"entries\":[",
|
||||
(unsigned)r.stats.mode,
|
||||
(unsigned long)r.stats.snapshot_seq,
|
||||
(unsigned long)r.stats.rx_count,
|
||||
(unsigned long)r.stats.tx_count,
|
||||
(unsigned long)r.stats.rx_drop_count,
|
||||
(unsigned long)r.stats.error_count,
|
||||
(unsigned)r.stats.tec,
|
||||
(unsigned)r.stats.rec,
|
||||
(unsigned)r.stats.bus_state,
|
||||
(unsigned)r.total_count);
|
||||
for (uint8_t j = 0; j < r.total_count && j < CANFD_ID_SNAPSHOT_MAX; ++j) {
|
||||
const id_snapshot_entry_t &e = r.entries[j];
|
||||
@@ -836,8 +840,12 @@ esp_err_t can_mode_handler(httpd_req_t *req)
|
||||
int requested = (int)cJSON_GetNumberValue(mode_item);
|
||||
cJSON_Delete(root);
|
||||
|
||||
can_rx_mode_t target = (requested == 1) ? CAN_RX_MODE_FILTER_ID
|
||||
: CAN_RX_MODE_ALL_PASS;
|
||||
can_rx_mode_t target = CAN_RX_MODE_ALL_PASS;
|
||||
if (requested == 1) {
|
||||
target = CAN_RX_MODE_FILTER_ID;
|
||||
} else if (requested == 2) {
|
||||
target = CAN_RX_MODE_BRIDGE_0_TO_12;
|
||||
}
|
||||
can_rx_mode_t actual = CAN_RX_MODE_ALL_PASS;
|
||||
int rc = canFdSetRxMode(target, &actual, 500);
|
||||
|
||||
@@ -1258,7 +1266,7 @@ esp_err_t system_status_handler(httpd_req_t *req)
|
||||
"\"internal_heap_total\": %lu, \"default_heap_total\": %lu, "
|
||||
"\"temperature\": %.1f, \"uptime_sec\": %lu, "
|
||||
"\"wifi\": {\"mode\": \"%s\", \"ip\": \"%s\", \"rssi\": %d, \"connected\": %s}, "
|
||||
"\"ota\": {\"sys_state\": \"%s\", \"sys_state_code\": %d, \"total_size\": %lu, \"stored_size\": %lu, \"storage_done\": %s, "
|
||||
"\"ota\": {\"sys_state\": \"%s\", \"sys_state_code\": %d, \"channel\": %d, \"channel_name\": \"%s\", \"total_size\": %lu, \"stored_size\": %lu, \"storage_done\": %s, "
|
||||
"\"relay_state\": %d, \"relay_seq\": %lu, \"relay_total_packets\": %lu, \"gd32_app_alive\": %s, "
|
||||
"\"gd32_app\": \"v%d.%d.%d.%d\", \"gd32_boot\": \"v%d.%d.%d.%d\"}, ",
|
||||
FW_VERSION, FW_BUILD_TIME, FW_GIT_HASH, HealthMonitor::instance().getCurrent(),
|
||||
@@ -1278,6 +1286,8 @@ esp_err_t system_status_handler(httpd_req_t *req)
|
||||
connected ? "true" : "false",
|
||||
snap.sys_state_str,
|
||||
(int)snap.sys_state,
|
||||
(int)snap.channel,
|
||||
snap.channel == OTA_CHANNEL_BLE ? "BLE" : "WIFI",
|
||||
(unsigned long)snap.meta.total_size,
|
||||
(unsigned long)snap.meta.stored_size,
|
||||
snap.storage_done ? "true" : "false",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* canfd_bridge.cpp - CANFD 3通道通信桥接实现(M4: 从 SpiMaster 提取)
|
||||
*/
|
||||
#include <string.h>
|
||||
@@ -109,7 +109,7 @@ int canFdPollFeedback(can_channel_t channel,
|
||||
out->valid = 0;
|
||||
uint8_t entryIdx = 0U;
|
||||
|
||||
constexpr uint8_t kFixedHeader = 25U; /* ch+page+total+cnt+mode+seq+rx+tx+drop+err */
|
||||
constexpr uint8_t kFixedHeader = 28U; /* ch+page+total+cnt+mode+seq+rx+tx+drop+err+tec+rec+bus_state */
|
||||
|
||||
for (uint8_t page = 0U; page < 2U; ++page) {
|
||||
uint8_t req[2] = { static_cast<uint8_t>(channel & CAN_CHANNEL_MASK), page };
|
||||
@@ -134,6 +134,9 @@ int canFdPollFeedback(can_channel_t channel,
|
||||
out->stats.tx_count = readU32Le(&resp_buf[13]);
|
||||
out->stats.rx_drop_count = readU32Le(&resp_buf[17]);
|
||||
out->stats.error_count = readU32Le(&resp_buf[21]);
|
||||
out->stats.tec = resp_buf[25];
|
||||
out->stats.rec = resp_buf[26];
|
||||
out->stats.bus_state = resp_buf[27];
|
||||
out->total_count = resp_buf[2];
|
||||
}
|
||||
|
||||
@@ -250,7 +253,7 @@ int canFdSetRxMode(can_rx_mode_t mode,
|
||||
can_rx_mode_t *actual,
|
||||
uint32_t timeout_ms)
|
||||
{
|
||||
if (mode != CAN_RX_MODE_ALL_PASS && mode != CAN_RX_MODE_FILTER_ID) {
|
||||
if (mode != CAN_RX_MODE_ALL_PASS && mode != CAN_RX_MODE_FILTER_ID && mode != CAN_RX_MODE_BRIDGE_0_TO_12) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* canfd_bridge.h - CANFD 3通道通信桥接(M4: 从 SpiMaster 提取)
|
||||
*
|
||||
* 封装 CANFD 帧格式构建 + SPI 传输,与 SpiMaster 的 OTA 协议职责解耦。
|
||||
@@ -91,6 +91,7 @@ typedef struct {
|
||||
typedef enum {
|
||||
CAN_RX_MODE_ALL_PASS = 0, ///< 默认:禁用 ID 过滤,三路全部接收
|
||||
CAN_RX_MODE_FILTER_ID = 1, ///< 按 CONFIG_CAN_RX_FILTER_ID/MASK 做标准帧过滤
|
||||
CAN_RX_MODE_BRIDGE_0_TO_12 = 2, ///< CAN0 桥接:CAN0 收到的每一帧按原帧格式自动转发到 CAN1 与 CAN2
|
||||
} can_rx_mode_t;
|
||||
|
||||
/**
|
||||
@@ -104,6 +105,9 @@ typedef struct {
|
||||
uint32_t tx_count;
|
||||
uint32_t rx_drop_count;
|
||||
uint32_t error_count;
|
||||
uint8_t tec; /**< 硬件发送错误计数器 (0~255) */
|
||||
uint8_t rec; /**< 硬件接收错误计数器 (0~255) */
|
||||
uint8_t bus_state; /**< 总线状态位图:bit0=init,bit1=sleep,bit2=error_passive,bit3=bus_off,bit4=error_warning */
|
||||
} can_channel_feedback_t;
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user