feat(comm): 1.6.51 CAN 空通道自动静默 + PDO 诊断 + OTA 布局共用头
变更点: 1. CAN-FD(device/CANFD.cpp、sys/config.h) - 发送统一 FD+BRS(DLC≤8 不再回退经典 CAN);OTA 期仍按通道压制 BRS - 空通道自动识别:连续 5 个 1Hz 窗口无有效帧且有错误 → 静默上报;有帧即恢复 - 三路 CAN 默认全开;RX parse budget 48→64 2. EtherCAT 桥 / PDO - 段1 增 txtxid/rx00ff;版本应答 0x00FF 粘滞发布,避免被 CONFIG 冲掉 - STATUS 禁止写入 xrx 快照;processSeq 新鲜度救援 3. OTA / 配置 - sys/config.h include 仓库内 shared/ota_layout.h(与 BOOT 共用,不再依赖仓外路径) - ota_boot_request 对齐配置页 word 布局 4. docs/audit_ecat_spi_wifi_ota_compatibility.md:ECAT/SPI/WiFi/OTA 兼容性审计 5. .gitignore:忽略 .trae/、docs/traework-import、评审过程稿
This commit is contained in:
@@ -36,13 +36,10 @@ static inline bool releaseFifo0(uint32_t canPeriph)
|
||||
CAN_RFIFO0(canPeriph) = CAN_RFIFO0_RFD0;
|
||||
for (uint32_t n = 0U; n < 2000U; ++n) {
|
||||
if ((CAN_RFIFO0(canPeriph) & CAN_RFIFO0_RFD0) == 0U) {
|
||||
/* 1.6.11 注:这里曾加过 128/2048 拍的 settle 延迟,假设"自清后 MDATA
|
||||
* 还在搬运"是装载时间竞态 —— 实测无效(正弦指令负载下拼接率不变)。
|
||||
* 节点指纹实验证明拼接是 FIFO 缓冲指针与帧边界失同步(node3 的
|
||||
* STATUS 帧头 24B = node2 的完整 CONFIG,错位恰为 CONFIG 帧长 6 字),
|
||||
/* 节点指纹实验表明拼接是 FIFO 缓冲指针与帧边界失同步
|
||||
* (STATUS 帧头 24B = 完整 CONFIG,错位恰为 CONFIG 帧长 6 字),
|
||||
* 不是延迟能挡的;结构矛盾的帧由 handleRxInterrupt 的内容校验计数
|
||||
* (1.6.12 起只计不丢 —— 管道必须诚实;源头修复见 1.6.13 的
|
||||
* CONFIG_IRQ_PREEMPT_CAN_RX=0)。 */
|
||||
* (只计不丢 —— 管道必须诚实;源头修复见 CONFIG_IRQ_PREEMPT_CAN_RX)。 */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -55,7 +52,7 @@ static inline bool releaseFifo0(uint32_t canPeriph)
|
||||
* 地址 CAN_RFIFOMDATA0 连读 dlen/4 次才取完(48B = 12 次),加上头部两次,一条
|
||||
* 帧就是十几次有先后依赖的总线访问,整个过程**不是原子的**。若这期间硬件把下
|
||||
* 一帧搬进邮箱窗口,就会读出"前几个字属于上一帧、后几个字属于这一帧"的拼接
|
||||
* 体,而 id/dlc 取自最开始那次读 —— 实测表现为 STATUS 帧的 ID 配上 CONFIG 帧
|
||||
* 体,而 id/dlc 取自最开始那次读 —— 表现为 STATUS 帧的 ID 配上 CONFIG 帧
|
||||
* 的前 12~24 字节,且混合边界 100% 落在 4 字节边界上。
|
||||
*
|
||||
* 判据用 MP 寄存器:TS[31:16] 是硬件接收时间戳、DLENC[3:0] 是长度,同一帧内两
|
||||
@@ -67,8 +64,8 @@ static bool receiveFrameChecked(uint32_t canPeriph, can_receive_message_struct *
|
||||
{
|
||||
/* 整段取数放进 BASEPRI 临界区:屏蔽 preempt>=1,把 EtherCAT 的 ESC(1)/SYNC1(1)
|
||||
* 挡在外面。取数是十几次有先后依赖的寄存器读,被抢占就会读出跨帧拼接体。
|
||||
* 1.6.13 起本 ISR 自身就是 preempt=0(CONFIG_IRQ_PREEMPT_CAN_RX),与 SYNC0
|
||||
* 同级互不抢占,取数自此真正原子;MI/MP 回读校验保留,作为对硬件自发换帧
|
||||
* 本 ISR 自身是 preempt=0(CONFIG_IRQ_PREEMPT_CAN_RX),与 SYNC0
|
||||
* 同级互不抢占,取数真正原子;MI/MP 回读校验保留,作为对硬件自发换帧
|
||||
* (dequeue 异步完成等)的兜底观测 —— rx_torn 计数即"该病理是否还在发生"。 */
|
||||
const uint32_t basepri = RT_CRITICAL_SAVE();
|
||||
|
||||
@@ -109,7 +106,7 @@ static bool receiveFrameChecked(uint32_t canPeriph, can_receive_message_struct *
|
||||
/* 取数后回读 MI+MP:任一变化 ⇒ 邮箱窗口在取数期间被换帧,这一帧是拼接体。
|
||||
* 必须连 MI(完整 ID)一起比 —— 只比 MP 的 TS/DLENC 会漏:TS 是 16 位计数器,
|
||||
* 相邻两帧可能同值,DLENC 也常常相同(都是 48),于是"ID 报 STATUS、数据却是
|
||||
* CONFIG"这种错配能从校验里溜过去(实测占坏帧的绝大多数)。ID 变了就一定是
|
||||
* CONFIG"这种错配能从校验里溜过去。ID 变了就一定是
|
||||
* 换了帧,这条判据没有巧合空间。 */
|
||||
const uint32_t keep = CAN_RFIFOMP_TS | CAN_RFIFOMP_DLENC;
|
||||
const uint32_t mp1 = CAN_RFIFOMP(canPeriph, CAN_FIFO0);
|
||||
@@ -419,13 +416,11 @@ bool CanFd::initNominalTiming(uint32_t canPeriph)
|
||||
can_parameter.auto_bus_off_recovery = ENABLE;
|
||||
can_parameter.auto_wake_up = DISABLE;
|
||||
can_parameter.auto_retrans = ENABLE; /* 默认自动重发兜底偶发 ACK 丢失;OTA 停等协议期间由 setChannelAutoRetrans(ch,false) 临时关闭,避免重发打穿电机单缓冲 RX */
|
||||
/* 1.6.11 真根因:这里曾是 ENABLE —— FIFO 满时**覆盖最旧邮箱**,而最旧邮箱
|
||||
* 正是 CPU 正在读取的输出窗口。buildInput 在 PDI_Isr(preempt1) 占 ~357µs
|
||||
* 会压住 CAN ISR(preempt2),发指令时电机 CONFIG 翻倍到 2kHz/节点、总线
|
||||
* ~8kHz,阻塞窗口内到达 ~3 帧恰好打满 FIFO 深度 → 覆盖进行到一半被读走
|
||||
* = 跨节点/跨类型拼接帧(指纹实验实锤:node2 的 CONFIG 条目带 node3 的
|
||||
* 速度限 150 与反相角度;settle 延迟/重取/MI-MP 校验都挡不住,因为
|
||||
* MI/MP 是覆盖序列里最后更新的一环)。DISABLE = 溢出丢新帧并置 RFO0
|
||||
/* rec_fifo_overwrite = DISABLE:FIFO 满时丢新帧而非覆盖最旧邮箱。
|
||||
* 覆盖最旧会伤及 CPU 正在读取的输出窗口。buildInput 在 PDI_Isr(preempt1)
|
||||
* 占 ~357µs 会压住 CAN ISR(preempt2),发指令时电机 CONFIG 翻倍到 2kHz/节点、
|
||||
* 总线 ~8kHz,阻塞窗口内到达 ~3 帧恰好打满 FIFO 深度 → 覆盖进行到一半被读走
|
||||
* = 跨节点/跨类型拼接帧。DISABLE 后溢出丢新帧并置 RFO0
|
||||
* (rx_fifo_overfull_count 已在统计):STATUS/CONFIG 均周期量,丢一拍下拍
|
||||
* 即补;覆盖递上来的才是网页乱码。与本文件软件队列"满丢新不覆旧"同则。 */
|
||||
can_parameter.rec_fifo_overwrite = DISABLE;
|
||||
@@ -579,7 +574,7 @@ void CanFd::initChannelHardware(uint8_t i)
|
||||
CAN_TSTAT(ch.canPeriph) = CAN_TSTAT_MTF0 | CAN_TSTAT_MTF1 | CAN_TSTAT_MTF2;
|
||||
can_interrupt_enable(ch.canPeriph, CAN_INT_TME | CAN_INT_RFNE0 | CAN_INT_RFF0 | CAN_INT_RFO0);
|
||||
nvic_irq_enable(ch.txIrq, CONFIG_IRQ_PREEMPT_CAN, static_cast<uint8_t>(i));
|
||||
/* 1.6.13:RX 提到 preempt=0 —— 见 sys/config.h CONFIG_IRQ_PREEMPT_CAN_RX 注释。 */
|
||||
/* RX 提到 preempt=0 —— 见 sys/config.h CONFIG_IRQ_PREEMPT_CAN_RX 注释。 */
|
||||
nvic_irq_enable(ch.rx0Irq, CONFIG_IRQ_PREEMPT_CAN_RX, static_cast<uint8_t>(i));
|
||||
|
||||
s_rxQueues[i].head = 0U;
|
||||
@@ -946,7 +941,7 @@ void CanFd::init()
|
||||
|
||||
/**
|
||||
* @brief L0 轻量自检:无总线发帧,仅校验使能通道控制器自身状态(GD32 侧故障)。
|
||||
* @note 1.5.35:不再检查 BUS_OFF/TEC/REC——未接从站的通道 RX 浮空噪声会累积 REC,
|
||||
* @note 不检查 BUS_OFF/TEC/REC——未接从站的通道 RX 浮空噪声会累积 REC,
|
||||
* 「没接设备」不等于错误;总线侧健康由 0xC1 反馈帧运行期上报。
|
||||
*/
|
||||
bool CanFd::selfTestL0(uint8_t *fault_code, uint8_t *fault_channel)
|
||||
@@ -1136,11 +1131,13 @@ CanFd::CanTxResult CanFd::transmitFrame(uint8_t channelIndex, uint32_t ext_id,
|
||||
tx_msg.tx_ft = CAN_FT_DATA;
|
||||
tx_msg.tx_dlen = dlc;
|
||||
#ifdef GD32E508
|
||||
tx_msg.fd_flag = (dlc > 8U) ? ENABLE : DISABLE;
|
||||
/* 只要通道硬件已启用 CAN-FD(3路均由 initFdMode 开启),统一发 FD 帧;
|
||||
* 避免 DLC<=8 时回退经典 CAN 导致对端电机 DMA / 报文解析异常。 */
|
||||
tx_msg.fd_flag = ENABLE;
|
||||
#if (CONFIG_CAN_FD_BRS_ENABLE != 0)
|
||||
/* 电机 BOOT 收不了 BRS 数据段,OTA 期间 relay 对该通道压制(setChannelBrsSuppress),
|
||||
* DLC>8 帧回仲裁段速率(FD-no-BRS,OTA 长期验证过的组合)。 */
|
||||
tx_msg.fd_brs = (dlc > 8U && !s_brsSuppress[channelIndex]) ? ENABLE : DISABLE;
|
||||
* 压制中回退仲裁段速率(FD-no-BRS,OTA 长期验证过的组合)。日常发送统一启用 BRS 高速段。 */
|
||||
tx_msg.fd_brs = (!s_brsSuppress[channelIndex]) ? ENABLE : DISABLE;
|
||||
#else
|
||||
tx_msg.fd_brs = DISABLE;
|
||||
#endif
|
||||
@@ -1467,24 +1464,18 @@ void CanFd::handleRxInterrupt(uint8_t channelIndex)
|
||||
/* 自己取帧并校验(见 receiveFrameChecked):厂商库不校验也不等 RFD 自清,
|
||||
* 会把"半条上一帧 + 半条本帧"的拼接体当正常帧交上来。
|
||||
*
|
||||
* 1.6.10:**校验失败只丢不重取**。1.6.7 起这里是"原地重取最多 3 次",
|
||||
* 实测被证伪为撕裂的直接制造者:RFIFOMDATA0 是"重复读同一地址、硬件读
|
||||
* 指针自动前进"(厂商驱动证实),attempt1 失败时读指针已随取数前进若干
|
||||
* 字,重取的 attempt2 从错位指针开读 —— MI/MP 回读比对的是"窗口身份",
|
||||
* **校验失败只丢不重取**。RFIFOMDATA0 是"重复读同一地址、硬件读
|
||||
* 指针自动前进",取数失败时读指针已随取数前进若干字,
|
||||
* 重取会从错位指针开读 —— MI/MP 回读比对的是"窗口身份",
|
||||
* 管不住"指针相对窗口起点的错位",于是校验通过、内容却是"上一帧的尾巴
|
||||
* 拼下一帧的开头"。自测实锤:重取版 1.6.9 在电机活跃时错标率 9.155%
|
||||
* (56835/620838),而 rx_torn 全程恒 0 —— 拼接恰好都从校验里溜过去。
|
||||
* 丢帧无害:STATUS/CONFIG 都是 1kHz 周期量,下拍即补;递上去才会变乱码。
|
||||
* CAN ISR 是 preempt=2,EtherCAT 的 SYNC(0)/ESC(1)/SYNC1(1) 都能抢占它,
|
||||
* 这正是取数被打断的来源,也解释了为什么只有 EtherCAT 链路上看得到拼接、
|
||||
* WiFi 链路干净。 */
|
||||
* 拼下一帧的开头"。
|
||||
* 丢帧无害:STATUS/CONFIG 都是 1kHz 周期量,下拍即补;递上去才会变乱码。 */
|
||||
const bool intact = receiveFrameChecked(ch.canPeriph, &rx_message);
|
||||
if (!releaseFifo0(ch.canPeriph)) {
|
||||
s_diag.rx_release_timeout_count++;
|
||||
}
|
||||
if (!intact) {
|
||||
/* 校验判为拼接:整帧作废,不计 rx_count、不入队、不转发。
|
||||
* 本版起 rx_torn_count 恢复真实语义 —— 它恒 0 说明校验没在挡东西。 */
|
||||
/* 校验判为拼接:整帧作废,不计 rx_count、不入队、不转发。 */
|
||||
s_diag.rx_torn_count++;
|
||||
continue;
|
||||
}
|
||||
@@ -1494,28 +1485,25 @@ void CanFd::handleRxInterrupt(uint8_t channelIndex)
|
||||
const uint32_t rxId = (rx_message.rx_ff == CAN_FF_STANDARD)
|
||||
? rx_message.rx_sfid : rx_message.rx_efid;
|
||||
|
||||
/* ── 1.6.11:内容级拼接帧拦截 ──
|
||||
* MI/MP 回读校验管不住 FIFO 缓冲指针与帧边界的失同步(1.6.10 的
|
||||
* settle 延迟实测无效,指纹实验证明 node3 的 STATUS 帧头 24B 可以是
|
||||
* node2 的完整 CONFIG —— 错位恰为 CONFIG 帧长 6 字,与混合帧长交错
|
||||
* 相关,是 CAN IP 的指针病理,软件无法从取数时序上根除)。
|
||||
* 改为在入队前做结构自洽校验:拼接帧的 (id, data) 必矛盾,而真帧必自洽。
|
||||
/* ── 内容级拼接帧拦截 ──
|
||||
* MI/MP 回读校验管不住 FIFO 缓冲指针与帧边界的失同步
|
||||
* (指针病理,软件无法从取数时序上根除)。
|
||||
* 在入队前做结构自洽校验:拼接帧的 (id, data) 必矛盾,而真帧必自洽。
|
||||
* STATUS(0x000N0100, dlc48):CONFIG 头灌入必然把 MCU/Motor 温度推出
|
||||
* [-40,125]℃ 物理量程(CONFIG B0-1 = 03+限压低字节 → 123~250℃ 或
|
||||
* 负值),母线电压同步失序;
|
||||
* CONFIG(0x000N0101, dlc24):DBC v0.74 规定 B15-23 未使用恒 0,
|
||||
* STATUS 体灌入几乎必非 0;模式字节限 0..7(电机模式表最大 7)。
|
||||
* 命中即计数(1.6.12 起不再丢帧——管道必须诚实,计数仅做"源头是否
|
||||
* 还在产拼接帧"的测量):源头修复生效后本计数应恒 0,非 0 即失效告警。
|
||||
* 计数经段5@494 上报。
|
||||
* 残余风险:限压字节恰使温度落回量程内的理论组合(24V 台架实测限压
|
||||
* ≥15V → 对应"温度"≥153℃,仍在量程外),可接受。 */
|
||||
* 命中即计数(不丢帧——管道必须诚实,计数仅做"源头是否
|
||||
* 还在产拼接帧"的测量):源头修复生效后本计数应恒 0,非 0 即失效告警。
|
||||
* 计数经段5@494 上报。
|
||||
* 残余风险:限压字节恰使温度落回量程内的理论组合
|
||||
* (24V 台架实测限压 ≥15V → 对应"温度"≥153℃,仍在量程外),可接受。 */
|
||||
{
|
||||
const uint16_t idLo = (uint16_t)(rxId & 0xFFFFU);
|
||||
bool reject = false;
|
||||
/* 上一帧已接受的温度/电压(按节点):拼接帧的 CONFIG 字节可能恰好落进
|
||||
* 静态量程(实测 vel=150 指纹时 0301→2.59℃、5a00→0.9℃、cace→52.9V
|
||||
* 全部"合法"漏过),但绝不可能在 1ms 帧间隔里物理地跳过去 —— 斜率判据
|
||||
* 静态量程,但绝不可能在 1ms 帧间隔里物理地跳过去 —— 斜率判据
|
||||
* 是静态量程补不上的洞。阈值留 3 个数量级余量:温度 20℃/帧(实际
|
||||
* ≤0.005℃),电压 5V/帧(实际 ≤0.05V)。 */
|
||||
static int16_t s_lastMcu[16];
|
||||
@@ -1540,7 +1528,7 @@ void CanFd::handleRxInterrupt(uint8_t channelIndex)
|
||||
if (dmcu < 0) { dmcu = (int16_t)-dmcu; }
|
||||
if (dmot < 0) { dmot = (int16_t)-dmot; }
|
||||
/* 只比温度斜率:拼接帧的 CONFIG 头必然把 mcu/mot 推出 20℃/帧
|
||||
* (实测最小跳变 35℃,而真实温度 ≤0.005℃/帧,4 个数量级余量)。
|
||||
* (实际温度 ≤0.005℃/帧,4 个数量级余量)。
|
||||
* 电压不比斜率 —— 正弦换向/堵转时母线真实跌落可超 5V/帧,
|
||||
* 误杀会让显示冻结;拼接的电压特征(≈48V)已由量程+温度斜率兜住。 */
|
||||
if (dmcu > 2000 || dmot > 2000) {
|
||||
@@ -1564,8 +1552,8 @@ void CanFd::handleRxInterrupt(uint8_t channelIndex)
|
||||
}
|
||||
}
|
||||
if (reject) {
|
||||
/* 1.6.12:只计不丢 —— 数据管道必须诚实(用户裁定:过滤是遮羞布,
|
||||
* 修的是采集源头)。网页/ESP32/主站看到的就是源头产出的原始字节,
|
||||
/* 只计不丢 —— 数据管道必须诚实。
|
||||
* 网页/ESP32/主站看到的就是源头产出的原始字节,
|
||||
* 本计数退化为纯测量仪表:源头修好 = 恒 0;还在涨 = 源头问题仍在,
|
||||
* 且网页如实显示着,不存在"看着干净其实坏了"。 */
|
||||
s_diag.rx_content_reject_count++;
|
||||
@@ -1737,6 +1725,15 @@ void CanFd::handleTxInterrupt(uint8_t channelIndex)
|
||||
drainTxQueueIsr(channelIndex);
|
||||
}
|
||||
|
||||
/* ── 空通道自动识别状态(2026-09-18)──
|
||||
* 无对端的通道 RX 浮空 → 持续 STUFF、REC 冲 ~130 停在 ERR_PASSIVE,每 5s 刷一行
|
||||
* [CAN-HW-ERR](config.h 老注释"CH1/CH2 未接设备,关闭避免持续 CAN 错误 + 占 SPI
|
||||
* 带宽")。改为运行时自动判定:连续 CONFIG_CAN_QUIET_WINDOW 个窗口无有效帧增量
|
||||
* 且有错误 → 静默上报;出现帧增量立刻恢复。只抑制上报,硬件保持 NORMAL 接收。 */
|
||||
static uint8_t s_chanQuiet[3] = {0U, 0U, 0U}; /* 1=该通道已自动静默上报 */
|
||||
static uint32_t s_rxCountPrev[3] = {0U, 0U, 0U}; /* 上一拍末尾的 rx_count */
|
||||
static uint8_t s_quietMiss[3] = {0U, 0U, 0U}; /* 连续"无帧且有错"的窗口数 */
|
||||
|
||||
/**
|
||||
* @brief 刷新三路 CAN 通道的 1Hz 反馈快照。
|
||||
* @note 在临界区内拷贝实时计数与最近一帧信息到 s_feedback;保证 SPI 命令读到一致快照。
|
||||
@@ -1766,6 +1763,37 @@ void CanFd::refreshFeedbackSnapshot()
|
||||
}
|
||||
|
||||
s_feedbackSeq++;
|
||||
/* 空通道自动识别:本拍无有效帧增量且有错误 → 记一次 miss,连续达到窗口长度才静默
|
||||
* (加滞回,避免偶发丢拍/慢流量误判);一旦有帧增量立刻恢复上报。
|
||||
* 时间基 = s_feedbackSeq(本函数 1Hz,见下面 %5 的 5s 打印节拍)。 */
|
||||
for (size_t i = 0; i < kChannelCount; ++i) {
|
||||
const uint32_t rxNow = s_channelStats[i].rx_count;
|
||||
const uint32_t rxDelta = rxNow - s_rxCountPrev[i];
|
||||
s_rxCountPrev[i] = rxNow;
|
||||
const bool hasErr = (hw_tec[i] != 0U || hw_rec[i] != 0U
|
||||
|| (hw_err[i] & (CAN_ERR_WERR | CAN_ERR_PERR | CAN_ERR_BOERR)) != 0U);
|
||||
if (rxDelta > 0U) {
|
||||
s_quietMiss[i] = 0U;
|
||||
if (s_chanQuiet[i] != 0U) {
|
||||
s_chanQuiet[i] = 0U;
|
||||
CAN_LOGI("[CAN] CH%u 恢复上报:检测到有效帧 (rx=%lu)\r\n",
|
||||
static_cast<unsigned>(i), static_cast<unsigned long>(rxNow));
|
||||
}
|
||||
} else if (hasErr) {
|
||||
if (s_quietMiss[i] < 0xFFU) s_quietMiss[i]++;
|
||||
if (s_chanQuiet[i] == 0U
|
||||
&& s_feedbackSeq >= CONFIG_CAN_QUIET_AFTER_SEC
|
||||
&& s_quietMiss[i] >= CONFIG_CAN_QUIET_WINDOW_SEC) {
|
||||
s_chanQuiet[i] = 1U;
|
||||
LOG_ERR("[CAN] CH%u 无有效帧且错误累积 → 自动静默上报(本通道无设备/无对端;"
|
||||
"硬件保持接收,插上设备有帧即自动恢复;TEC=%lu REC=%lu)\r\n",
|
||||
static_cast<unsigned>(i),
|
||||
static_cast<unsigned long>(hw_tec[i]), static_cast<unsigned long>(hw_rec[i]));
|
||||
}
|
||||
} else {
|
||||
s_quietMiss[i] = 0U;
|
||||
}
|
||||
}
|
||||
/* 每 5 秒采样硬件错误态;正常心跳不打印(统计走 SPI 0xC1)。
|
||||
* 仅当 TEC/REC 或告警位非零时输出 [CAN-HW-ERR];全量 seq 心跳见 CONFIG_UART_DIAG_LEVEL。 */
|
||||
if (s_feedbackSeq % 5U == 0U) {
|
||||
@@ -1781,6 +1809,7 @@ void CanFd::refreshFeedbackSnapshot()
|
||||
&& (hw_err[i] & (CAN_ERR_WERR | CAN_ERR_PERR | CAN_ERR_BOERR)) == 0U) {
|
||||
continue;
|
||||
}
|
||||
if (s_chanQuiet[i] != 0U) continue; /* 已自动静默的空通道:不再刷错误 */
|
||||
LOG_ERR("[CAN-HW-ERR] CH%u ERR=0x%08lX ERRN=%lu(%s) TEC=%lu REC=%lu TSTAT=0x%08lX\r\n",
|
||||
static_cast<unsigned>(i),
|
||||
static_cast<unsigned long>(hw_err[i]),
|
||||
@@ -1814,6 +1843,10 @@ void CanFd::refreshFeedbackSnapshot()
|
||||
for (size_t i = 0; i < kChannelCount; ++i) {
|
||||
uint8_t cur = s_feedback[i].stats.bus_state;
|
||||
if (cur != s_prevBusState[i]) {
|
||||
if (s_chanQuiet[i] != 0U) { /* 静默通道的状态变化只记账不打印 */
|
||||
s_prevBusState[i] = cur;
|
||||
continue;
|
||||
}
|
||||
const char *stateStr = "NORMAL";
|
||||
if (cur & (1U << 0)) stateStr = "INIT_MODE";
|
||||
else if (cur & (1U << 3)) stateStr = "BUS_OFF";
|
||||
|
||||
Reference in New Issue
Block a user