Refactor and clean up codebase

- Removed unused constants and type aliases in app_spi_command_defs.h and temp_sensor.h.
- Simplified ISpiCommandHandler destructor to default.
- Eliminated redundant methods and comments in temp_sensor and usart0 files.
- Consolidated writeU32Le function to app_spi_command_defs.h for reuse.
- Updated comments for clarity and accuracy in task_manager.h and task_runner.cpp.
- Removed hardfault.h as it contained no declarations.
- Cleaned up CANFD and watchdog implementations by removing dead code and unnecessary comments.
- Updated version numbers in config.h to reflect recent changes.
- Enhanced error handling and diagnostics in hardfault handling.
This commit is contained in:
cbb
2026-07-15 02:49:37 +08:00
parent a52d94687b
commit 76da7a3dd6
37 changed files with 1401 additions and 1955 deletions
@@ -0,0 +1,256 @@
# 清理剩余低风险可优化项 Plan
## Summary
在上一轮 `purge-legacy-dead-code` spec(已清除 23 项 A 类死代码 + 11 项 B/C/D 类改进)基础上,对 `GD32E508_DCU_APP/` 进行二次扫描,识别并处理 **13 项剩余低风险可优化项**(不改变运行期行为,构建可验证)。
覆盖三类:
- **A 类残留死代码**(6 项):死别名、写而不读成员/静态、空头文件、冗余类型别名
- **过期/缺失注释**(3 项):PRIMASK 过期说明、taskHeartbeat 过期注释、复位前 PRIMASK 缺解释
- **重复代码提取**(4 项):spinDelay 延时循环、armRingPending 赋值模式、writeU32Le 跨文件去重、adc.cpp namespace 合并
## Current State Analysis
### 已完成(上一轮 spec)
- A1-A14:23 项死代码清除(CAN 兼容轮询链/SPI v1 状态机/EtherCAT 死 API/ADC/USART0/Watchdog/TempSensor 死接口等)
- B1-B6:6 项前瞻性桩加 TODO 标记
- C1-C4:4 项条件编译优化
- D1:1 项历史注释清理
- 构建验证通过(43/43,0 错误,Code=47462)
### 本轮新发现(经 Grep 交叉验证)
二次扫描发现 13 项上一轮未覆盖的低风险优化项,均不改变运行期行为。
## Proposed Changes
### 第一组:A 类残留死代码清除(6 项)
#### 1.1 删除死类型别名 `canfd_diag_t`
- **文件**:`GD32E508_DCU_APP/device/canfd.h:211`
- **现状**:`using canfd_diag_t = CanFd::Diag;` — Grep 全项目仅命中声明自身,无任何使用方
- **改法**:删除第 211 行及相邻空行
- **风险**:低(纯类型别名删除)
#### 1.2 删除写而永不读成员 `m_ringTxLen`
- **文件**:
- `GD32E508_DCU_APP/device/spi/app_spi_command.h:119-120`(声明 + 注释)
- `GD32E508_DCU_APP/device/spi/app_spi_command.cpp:407, 712, 745, 859, 867`(5 处写入)
- **现状**:`volatile uint16_t m_ringTxLen = 0U;` 头注释称"供 onCsAssert 装入 DMA",但 `onCsAssert` 实际使用的是 `m_txLen`。在 `requestEsp32Read`(745-746 行)中 `m_ringTxLen` 与 `m_txLen` 被赋同值,`m_ringTxLen` 是冗余写者。Grep 确认 5 处写入、0 处读取。
- **改法**:
1. 删除 `app_spi_command.h:119-120`(注释 + 成员声明)
2. 删除 `app_spi_command.cpp` 中 5 处 `m_ringTxLen = ...;` 赋值语句
- **风险**:低(仅删除写操作,`m_txLen` 与 `m_ringTxLen` 始终同值,读取路径不变)
- **注意**:745 行 `m_ringTxLen = (uint16_t)built_len;` 的下一行 `m_txLen = (uint16_t)built_len;` 必须保留
#### 1.3 删除写而永不读静态 `s_pushCount`
- **文件**:`GD32E508_DCU_APP/device/spi/app_spi_cmd_can_feedback.cpp:257, 282`
- **现状**:`static uint32_t s_pushCount = 0U;` 仅被自增(282 行 `++s_pushCount;`),从未被读取、打印或暴露给诊断接口
- **改法**:删除 257 行声明与 282 行自增语句(含其注释 `/* 仅保留计数,不打印心跳日志 */`)
- **风险**:低(纯死状态)
#### 1.4 删除 4 个未使用本地别名
- **文件**:`GD32E508_DCU_APP/device/spi/app_spi_command.cpp:49, 51, 54, 55`
- **现状**:本地别名块(48-56 行)共 9 个别名,其中 `kTypeCanSend`/`kTypeAppPing`/`kRspAck`/`kRspWait` 4 个在文件内从未被引用(Grep 仅命中声明行)。其余 5 个(`kTypeBootReq`/`kTypeOtaReq`/`kTypeOtaData`/`kTypeOtaCancel`/`kRspError`)仍被使用。
- **改法**:删除第 49、51、54、55 行
- **风险**:低(删除 `static constexpr` 未使用符号)
#### 1.5 删除空头文件 `sys/hardfault.h`
- **文件**:`GD32E508_DCU_APP/sys/hardfault.h`(整文件,仅 3 行 include guard)
- **现状**:A13 清理后该头文件已无任何声明,仅剩 `#ifndef HARDFAULT_H / #define HARDFAULT_H / #endif`。`sys/hardfault.cpp` 不包含此头,全项目无任何 `#include "sys/hardfault.h"` 或 `#include "hardfault.h"`(Grep 确认 0 匹配)。
- **改法**:删除整个文件
- **风险**:低(无引用方)
- **注意**:需确认构建脚本(CMakeLists.txt)中是否显式列出该头文件作为安装目标;若仅有 .cpp 参与编译则无影响
#### 1.6 删除 TempSensor 冗余类型别名(方案 A)
- **文件**:
- `GD32E508_DCU_APP/device/temp_sensor.h:12`(`using Data = Adc::Sample;`)
- `GD32E508_DCU_APP/device/temp_sensor.h:24`(`using temp_sensor_data_t = TempSensor::Data;`)
- `GD32E508_DCU_APP/sys/task_runner.cpp:62`(消费点 `temp_sensor_data_t sample{};`)
- **现状**:两层 `using` 别名链(`temp_sensor_data_t` → `TempSensor::Data` → `Adc::Sample`),仅 1 处消费(task_runner.cpp:62)。`TempSensor` 类本身保留(`init()` 仍被 `initial.cpp:45` 调用,作为语义门面有价值)。
- **改法**:
1. 删除 `temp_sensor.h:12` 的 `using Data = Adc::Sample;`
2. 删除 `temp_sensor.h:24` 的 `using temp_sensor_data_t = TempSensor::Data;`
3. 修改 `task_runner.cpp:62` 将 `temp_sensor_data_t sample{};` 改为 `Adc::Sample sample{};`
4. 确认 `task_runner.cpp` 已 `#include "device/adc.h"`(若未包含则需添加,但 task_runner.cpp 大概率已包含)
- **风险**:低(仅类型别名替换,不改语义)
- **注意**:`TempSensor` 类的 `init()` 声明与 doxygen 注释保留不动
---
### 第二组:过期/缺失注释修正(3 项)
#### 2.1 修正 `task_manager.h` PRIMASK 过期注释
- **文件**:`GD32E508_DCU_APP/sys/task_manager.h:45`
- **现状**:注释 `内部通过保持当前 PRIMASK 状态的临界区保证可由主循环与 ISR 共享调用`,但实现已迁移至 BASEPRI(`RT_CRITICAL_SAVE/RESTORE`)
- **改法**:改为 `内部通过 BASEPRI 临界区(RT_CRITICAL_SAVE/RESTORE)保证可由主循环与 ISR 共享调用`
- **风险**:低(纯注释)
#### 2.2 修正 `task_runner.cpp` taskHeartbeat 过期注释
- **文件**:`GD32E508_DCU_APP/sys/task_runner.cpp:225`
- **现状**:`taskHeartbeat` 的 doxygen 注释 `@note 当前仅保留任务入口。` 已过期失真——函数体实际已有实现(227 行:`OtaBootRequest::process(); CanFd::refreshFeedbackSnapshot(); canFeedbackStartRound();`)。相邻的 `taskStatusLed`(216 行)确实空体,其注释准确。
- **改法**:将 225 行注释改为 `@note 当前任务:推进 OTA Boot 请求、刷新 CAN 反馈快照、启动反馈推送轮次。`
- **风险**:低(纯注释)
- **注意**:`taskStatusLed` 的 216 行注释保持不动(空体桩是 B 类前瞻性桩)
#### 2.3 补充 `ota_boot_request.cpp` PRIMASK 解释注释
- **文件**:`GD32E508_DCU_APP/sys/ota_boot_request.cpp:220`
- **现状**:`__disable_irq(); NVIC_SystemReset();` 是全项目唯一使用 PRIMASK 而非 BASEPRI 的位置。这是**合法用法**(系统复位前最终屏蔽全部中断,防止复位过程中断嵌套),但缺乏解释,后续维护者可能误判为违反项目硬约束。
- **改法**:在 220 行前加注释:`/* 复位前最终关中断:必须用 PRIMASK 全屏蔽(非 BASEPRI),确保 NVIC_SystemReset 过程中无任何中断嵌套 */`
- **风险**:低(纯注释)
---
### 第三组:重复代码提取(4 项)
#### 3.1 提取 `spinDelay` 延时循环(CANFD.cpp)
- **文件**:`GD32E508_DCU_APP/device/CANFD.cpp`
- **现状**:9 处 `for (volatile uint32_t d = 0; d < NNNNN; ++d) {}` 纯延时循环散落在 `hardResetCan`、`runSelfTestFrame`、`init` 退出 init mode 兜底等多处。魔数 `{40000, 50000, 100000, 200000}` 无命名常量。
- **改法**:
1. 在文件顶部匿名 namespace 内新增:
```cpp
/* 纯软件延时循环(不依赖 SysTick,可在任何中断状态下使用) */
static inline void spinDelay(uint32_t loops) {
for (volatile uint32_t d = 0; d < loops; ++d) { }
}
```
2. 把以下**纯延时循环**(无 break/条件)替换为 `spinDelay(N);`:
- 94 行:`for (volatile uint32_t dly = 0; dly < 40000U; ++dly) { }` → `spinDelay(40000U);`
- 120 行:`for (volatile uint32_t d = 0; d < 100000U; ++d) {}` → `spinDelay(100000U);`
- 125 行:`for (volatile uint32_t d = 0; d < 50000U; ++d) {}` → `spinDelay(50000U);`
- 130 行:`for (volatile uint32_t d = 0; d < 200000U; ++d) {}` → `spinDelay(200000U);`
- 142 行:需确认是否纯延时(读取后判断)
- 382 行:需确认是否纯延时
- 384 行:需确认是否纯延时
3. **不替换**带有条件 break 的轮询等待循环(如 355 行 `for (...) { if ((CAN_STAT(...) & CAN_STAT_IWS) == 0U) break; }`)——这些不是纯延时,保持原样
- **风险**:低(纯结构提取,延时循环行为不变)
- **注意**:执行时需逐一 Read 确认 134/142/382/384 行的实际内容,仅替换纯延时循环
#### 3.2 提取 `armRingPending` 赋值模式(app_spi_command.cpp)
- **文件**:`GD32E508_DCU_APP/device/spi/app_spi_command.cpp`
- **现状**:7 处重复的"按铃挂起"赋值模式:
```
m_ringPending = true;
m_ringDeadline = SysTickTimer::getMs() + kRingTimeoutMs;
```
出现在 516-517, 556-557, 580-581, 604-605, 630-631, 699-700, 748-749 行。
- **改法**:
1. 在 `app_spi_command.h` 的 `AppSpiCommand` private 段新增声明:`void armRingPending();`
2. 在 `app_spi_command.cpp` 新增实现:
```cpp
void AppSpiCommand::armRingPending() {
m_ringPending = true;
m_ringDeadline = SysTickTimer::getMs() + kRingTimeoutMs;
}
```
3. 把 7 处两行赋值替换为 `armRingPending();`
- **风险**:低(语义等价提取,两个独立赋值无依赖关系,顺序无关)
- **注意**:第 7 处(748-749)原顺序为先 `m_ringDeadline` 后 `m_ringPending`,提取后顺序统一为方法内顺序,不影响语义
#### 3.3 `writeU32Le` 跨文件去重
- **文件**:
- `GD32E508_DCU_APP/device/spi/app_spi_cmd_can_feedback.cpp:53-59`(`static void writeU32Le`)
- `GD32E508_DCU_APP/device/spi/app_spi_cmd_id_snapshot.cpp:33-39`(`inline void writeU32Le`)
- **现状**:两个 SPI 命令处理器的匿名 namespace 各自定义了字节序相同的 `writeU32Le(uint8_t *dst, uint32_t val)`,实现完全一致(仅参数名 value/val 不同)。
- **改法**:
1. 在 `GD32E508_DCU_APP/device/spi/app_spi_command_defs.h` 末尾(`SpiDefs` namespace 外或内,视现有结构而定)新增:
```cpp
inline void writeU32Le(uint8_t *dst, uint32_t val) {
dst[0] = static_cast<uint8_t>(val & 0xFFU);
dst[1] = static_cast<uint8_t>((val >> 8) & 0xFFU);
dst[2] = static_cast<uint8_t>((val >> 16) & 0xFFU);
dst[3] = static_cast<uint8_t>((val >> 24) & 0xFFU);
}
```
2. 删除 `app_spi_cmd_can_feedback.cpp:53-59` 的本地 `writeU32Le` 定义
3. 删除 `app_spi_cmd_id_snapshot.cpp:33-39` 的本地 `writeU32Le` 定义
4. 确认两个 .cpp 已 `#include "device/spi/app_spi_command_defs.h"`(大概率已包含,因它们使用 `SpiDefs::kType*` 常量)
- **风险**:低(纯函数提取,实现完全一致)
#### 3.4 合并 `adc.cpp` 双重匿名 namespace
- **文件**:`GD32E508_DCU_APP/device/adc.cpp:12-27, 29-35`
- **现状**:同一文件有两个独立 `namespace { ... }` 块:
- 第一个(12-27):含 `kMinValidVdda` 等校验常量与 `isValidAdcRaw`/`isFiniteFloat`
- 第二个(29-35):含 `kDmaPeriph`/`kDmaChannel`/`s_dmaBuffer` 等 DMA 配置
- 语义上都属于文件内静态,无必要分两块
- **改法**:合并为单一 `namespace { ... }` 块,用空行 + 注释分隔逻辑分组:
```cpp
namespace {
/* ---- 校验常量与辅助函数 ---- */
constexpr float kMinValidVdda = 2.7f;
... (原第一块内容)
/* ---- DMA 配置 ---- */
constexpr uint32_t kDmaPeriph = DMA0;
... (原第二块内容)
} // namespace
```
- **风险**:低(纯结构调整)
---
## Assumptions & Decisions
### 假设
1. 上一轮 `purge-legacy-dead-code` spec 的所有修改已合并且构建通过(已确认:Code=47462)
2. `task_runner.cpp` 已 `#include "device/adc.h"`(因 `Adc::collectSample` 在 319 行被调用)
3. 两个 SPI 命令处理器 .cpp 已 `#include "device/spi/app_spi_command_defs.h"`(因使用 `SpiDefs::kType*` 常量)
4. CMake 构建脚本未显式安装 `sys/hardfault.h`(头文件通常不被列为编译目标)
### 决策
1. **3.1 spinDelay 仅提取纯延时循环**:带条件 break 的轮询等待循环(如 355 行)保持原样,避免改变语义
2. **1.6 TempSensor 保留类本身**:仅删冗余别名,`TempSensor::init()` 作为语义门面保留(`initial.cpp:45` 仍调用)
3. **不处理 3 项中风险项**:CANFD.cpp 文件名大小写、init() 重构、volatile 审计——需独立 spec
4. **不主动清理 #include**:即使某头文件因移除类型而变冗余,也不删除 #include(避免过度改动,构建不会因此报错)
## Verification Steps
### 1. Grep 验证(清除项零残留)
- `canfd_diag_t` → 0 匹配
- `m_ringTxLen` → 0 匹配
- `s_pushCount` → 0 匹配
- `kTypeCanSend|kTypeAppPing|kRspAck|kRspWait`(在 app_spi_command.cpp 内)→ 0 匹配
- `#include.*hardfault.h` → 0 匹配
- `temp_sensor_data_t` → 0 匹配
- `writeU32Le`(在 app_spi_cmd_can_feedback.cpp 和 app_spi_cmd_id_snapshot.cpp 内)→ 0 匹配(仅 app_spi_command_defs.h 中有定义)
### 2. Grep 验证(新增项存在)
- `spinDelay` 在 CANFD.cpp 中出现 ≥1 次(定义)+ N 次(调用)
- `armRingPending` 在 app_spi_command.h 中出现 1 次(声明)+ app_spi_command.cpp 中出现 1 次(定义)+ 7 次(调用)
- `writeU32Le` 在 app_spi_command_defs.h 中出现 1 次(定义)
- `BASEPRI 临界区` 在 task_manager.h:45 出现 1 次
- `推进 OTA Boot 请求` 在 task_runner.cpp 出现 1 次
- `复位前最终关中断` 在 ota_boot_request.cpp 出现 1 次
### 3. 构建验证
- `cmake --build g:\Robot_v2\DCU\DCU_APP\tmp\1 --clean-first`
- 0 编译错误
- 0 新增警告(`#warning` 仅来自上一轮 C1 的 EXMC,不计入)
- Program Size: Code 应略小于 47462(因删除了死代码)
### 4. 活跃代码完整性核查
- `Adc::collectSample` 仍被 task_runner.cpp 引用
- `TempSensor::init` 仍被 initial.cpp:45 引用
- `m_txLen`/`m_ringPending`/`m_ringDeadline` 成员完整保留
- `SpiDefs::kTypeCanSend` 等常量在 app_spi_command_defs.h 中完整保留(仅本地别名删除)
- `HardFault_Handler`/`HardFault_Handler_C` 在 hardfault.cpp 中完整保留
## 任务分组与执行顺序
### 可并行执行的三组(文件集不交叠)
**组 A:device/spi/ 目录(1.2 + 1.3 + 1.4 + 3.2 + 3.3)**
- 文件:`app_spi_command.h/.cpp`、`app_spi_cmd_can_feedback.cpp`、`app_spi_cmd_id_snapshot.cpp`、`app_spi_command_defs.h`
- 注意:3.2(armRingPending)和 1.2(m_ringTxLen)都改 `app_spi_command.h/.cpp`,需顺序执行
**组 B:device/ 目录(1.1 + 1.6 + 3.1 + 3.4)**
- 文件:`canfd.h`、`CANFD.cpp`、`temp_sensor.h`、`task_runner.cpp`、`adc.cpp`
- 注意:1.6 改 `temp_sensor.h` + `task_runner.cpp`;3.1 改 `CANFD.cpp`
**组 C:sys/ 目录(1.5 + 2.1 + 2.2 + 2.3)**
- 文件:`hardfault.h`(删除)、`task_manager.h`、`task_runner.cpp`、`ota_boot_request.cpp`
- 注意:2.2 和 1.6 都改 `task_runner.cpp`,需顺序执行或合并到同一子代理
### 建议执行顺序
1. 先并行执行组 A、组 B、组 C(三组文件集基本不交叠,仅 `task_runner.cpp` 跨组)
2. `task_runner.cpp` 的改动(1.6 改类型 + 2.2 改注释)合并到同一子代理
3. 最后执行构建验证