Files
DCU_APP/.trae/documents/cleanup-residual-low-risk-optimizations.md
T
cbb 76da7a3dd6 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.
2026-07-15 02:49:37 +08:00

257 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 清理剩余低风险可优化项 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. 最后执行构建验证