From 46ef19d88204f77a3954312894fbd8b07d3d9b0e Mon Sep 17 00:00:00 2001 From: cbb <2625274797@qq.com> Date: Mon, 27 Jul 2026 01:49:18 +0800 Subject: [PATCH] =?UTF-8?q?feat(build):=20=E4=BC=98=E5=8C=96=E6=9E=84?= =?UTF-8?q?=E5=BB=BA=E9=85=8D=E7=BD=AE=E5=B9=B6=E5=BC=95=E5=85=A5=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E5=88=86=E7=BA=A7=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将优化级别从balanced调整为size,减少Flash占用 - 添加hardfault.cpp文件以增强故障诊断能力 - 关闭RTTI和异常处理以移除libcppabi运行时(节省约2.5KB Flash) - 添加链接器参数输出未引用段与总量报告用于Flash尺寸分析 refactor(logging): 统一日志输出并实现编译时日志分级 - 将printf调用替换为模块化的日志宏(ECAT_LOGI、CAN_LOGI等) - 实现CONFIG_*_LOG_ENABLE编译开关控制各模块INFO级日志 - 错误和关键事件使用LOG_ERR恒定保留,其他日志可编译时裁剪 - 保持原有日志内容不变,但支持链接器自动回收未使用的格式字符串 --- DCU_APP.csolution.yml | 2 +- .../GD32E508_DCU_APP.cproject.yml | 6 ++ GD32E508_DCU_APP/comm/esc_exmc_bus.cpp | 14 ++-- GD32E508_DCU_APP/comm/ethercat_slave.cpp | 16 ++--- GD32E508_DCU_APP/device/CANFD.cpp | 64 +++++++++---------- GD32E508_DCU_APP/main.cpp | 22 +++---- GD32E508_DCU_APP/sys/config.h | 39 ++++++++++- GD32E508_DCU_APP/sys/hardfault.cpp | 3 +- GD32E508_DCU_APP/sys/motor_ota_relay.cpp | 52 +++++++-------- 9 files changed, 130 insertions(+), 88 deletions(-) diff --git a/DCU_APP.csolution.yml b/DCU_APP.csolution.yml index 7af6f0a..27f1bf4 100644 --- a/DCU_APP.csolution.yml +++ b/DCU_APP.csolution.yml @@ -44,7 +44,7 @@ solution: - type: Release debug: off - optimize: balanced + optimize: size # List related projects. projects: diff --git a/GD32E508_DCU_APP/GD32E508_DCU_APP.cproject.yml b/GD32E508_DCU_APP/GD32E508_DCU_APP.cproject.yml index c8c4182..b9b8337 100644 --- a/GD32E508_DCU_APP/GD32E508_DCU_APP.cproject.yml +++ b/GD32E508_DCU_APP/GD32E508_DCU_APP.cproject.yml @@ -22,6 +22,7 @@ project: - file: ./sys/aes128.cpp - file: ./sys/motor_ota_relay.h - file: ./sys/motor_ota_relay.cpp + - file: ./sys/hardfault.cpp - file: ./sys/cpp_stubs.cpp - file: ./sys/config.h - group: device @@ -123,6 +124,9 @@ project: - -std=gnu11 CPP: - -std=gnu++17 + # 全工程零使用 RTTI/异常(grep 验证),关闭以剥离 libcppabi 运行时(约 2.5 KB Flash) + - -fno-rtti + - -fno-exceptions ASM: - -DGD32E508 - -DGD32E50X @@ -132,3 +136,5 @@ project: Link: - --library_type=microlib - --entry=Reset_Handler + # 输出未引用段与总量报告,用于 Flash 尺寸归因 + - --info=unused,totals diff --git a/GD32E508_DCU_APP/comm/esc_exmc_bus.cpp b/GD32E508_DCU_APP/comm/esc_exmc_bus.cpp index d1c6b0b..a315515 100644 --- a/GD32E508_DCU_APP/comm/esc_exmc_bus.cpp +++ b/GD32E508_DCU_APP/comm/esc_exmc_bus.cpp @@ -25,7 +25,7 @@ bool EscExmcBus::init() { s_ok = false; - printf("[ECAT][EXMC] init: enable RCU clocks\r\n"); + ECAT_LOGI("[ECAT][EXMC] init: enable RCU clocks\r\n"); rcu_periph_clock_enable(RCU_GPIOD); rcu_periph_clock_enable(RCU_GPIOE); rcu_periph_clock_enable(RCU_AF); @@ -56,7 +56,7 @@ bool EscExmcBus::init() gpio_init(CONFIG_EXMC_NOE_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_NOE_PIN); gpio_init(CONFIG_EXMC_NWE_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_NWE_PIN); gpio_init(CONFIG_EXMC_NE1_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, CONFIG_EXMC_NE1_PIN); - printf("[ECAT][EXMC] init: GPIO configured (D0-D15/A16/A17/NOE/NWE/NE1)\r\n"); + ECAT_LOGI("[ECAT][EXMC] init: GPIO configured (D0-D15/A16/A17/NOE/NWE/NE1)\r\n"); /* * EXMC NOR/SRAM Region1:16-bit、非复用、异步写。 @@ -97,7 +97,7 @@ bool EscExmcBus::init() wr_timing = rw_timing; - printf("[ECAT][EXMC] init: applying NOR/SRAM Region1 params (16b, async, t_data=%u HCLK)\r\n", + ECAT_LOGI("[ECAT][EXMC] init: applying NOR/SRAM Region1 params (16b, async, t_data=%u HCLK)\r\n", (unsigned)rw_timing.asyn_data_setuptime); exmc_norsram_init(&norsram_init); @@ -109,21 +109,21 @@ bool EscExmcBus::init() const uint16_t probe_low = read16((uint32_t)0x0000U << 1U); const uint16_t probe_high = read16((uint32_t)0x0002U << 1U); const uint32_t probe_id = ((uint32_t)probe_high << 16) | probe_low; - printf("[ECAT][EXMC] init: Region1 enabled, probe id_lo=0x%04X id_hi=0x%04X (id=0x%08lX)\r\n", + ECAT_LOGI("[ECAT][EXMC] init: Region1 enabled, probe id_lo=0x%04X id_hi=0x%04X (id=0x%08lX)\r\n", (unsigned)probe_low, (unsigned)probe_high, (unsigned long)probe_id); /* 总线挂死(全 0/全 1)视为 EXMC 未就绪;chip ID 完整校验在 EscLan9252::init()。 */ if (probe_low == 0x0000U && probe_high == 0x0000U) { - printf("[ECAT][EXMC] init: FAIL, bus reads all-zero (check wiring/NE1/A16/timing)\r\n"); + LOG_ERR("[ECAT][EXMC] init: FAIL, bus reads all-zero (check wiring/NE1/A16/timing)\r\n"); return false; } if (probe_low == 0xFFFFU && probe_high == 0xFFFFU) { - printf("[ECAT][EXMC] init: FAIL, bus reads all-ones (check ESC power/NOE/NWE)\r\n"); + LOG_ERR("[ECAT][EXMC] init: FAIL, bus reads all-ones (check ESC power/NOE/NWE)\r\n"); return false; } s_ok = true; - printf("[ECAT][EXMC] init: OK, bus visible\r\n"); + ECAT_LOGI("[ECAT][EXMC] init: OK, bus visible\r\n"); return true; } diff --git a/GD32E508_DCU_APP/comm/ethercat_slave.cpp b/GD32E508_DCU_APP/comm/ethercat_slave.cpp index 8daed4b..2e7f782 100644 --- a/GD32E508_DCU_APP/comm/ethercat_slave.cpp +++ b/GD32E508_DCU_APP/comm/ethercat_slave.cpp @@ -32,14 +32,14 @@ uint8_t EthercatSlave::s_alState = 0U; void EthercatSlave::init() { - printf("[ECAT][SLAVE] init: begin\r\n"); + ECAT_LOGI("[ECAT][SLAVE] init: begin\r\n"); if (!EscLan9252::init()) { /* EXMC 总线未就绪:无法继续读芯片 ID 与 AL 状态,统一上报 FAIL。 */ s_chipId = 0U; s_alState = 0U; s_escReady = false; - printf("[ECAT][SLAVE] init: FAIL, ESC bus not ready\r\n"); + LOG_ERR("[ECAT][SLAVE] init: FAIL, ESC bus not ready\r\n"); s_inputWriteIdx = 0U; s_outputReadIdx = 0U; s_periodicSeq = 0U; @@ -50,7 +50,7 @@ void EthercatSlave::init() /* 第 1 层调试可观测性:读取芯片 ID 并打印 selfTest 结果 */ s_chipId = EscLan9252::readChipId(); const bool chipIdOk = (s_chipId == 0x87654321U); - printf("[ECAT][SLAVE] chip id=0x%08lX expected=0x%08lX selfTest=%s\r\n", + ECAT_LOGI("[ECAT][SLAVE] chip id=0x%08lX expected=0x%08lX selfTest=%s\r\n", (unsigned long)s_chipId, (unsigned long)0x87654321UL, chipIdOk ? "PASS" : "FAIL"); @@ -83,13 +83,13 @@ void EthercatSlave::init() * (如 SM Watchdog=0x1B、FMMU 配置错、邮箱协议错),需主站介入。 */ if (!chipIdOk) { - printf("[ECAT][SLAVE] ESC NOT ready, sync ISR disabled (check EXMC wiring/timing)\r\n"); + LOG_ERR("[ECAT][SLAVE] ESC NOT ready, sync ISR disabled (check EXMC wiring/timing)\r\n"); } else if (s_alState < AL_STATE_SAFEOP) { - printf("[ECAT][SLAVE] chip id PASS, but AL state=0x%02X(%s) < SAFEOP(0x%02X), code=0x%02X\r\n", + LOG_ERR("[ECAT][SLAVE] chip id PASS, but AL state=0x%02X(%s) < SAFEOP(0x%02X), code=0x%02X\r\n", (unsigned)s_alState, alStateName, (unsigned)AL_STATE_SAFEOP, (unsigned)alCode); - printf("[ECAT][SLAVE] SYNC0 will not fire, full ESC config requires SSC integration\r\n"); + LOG_ERR("[ECAT][SLAVE] SYNC0 will not fire, full ESC config requires SSC integration\r\n"); } else { - printf("[ECAT][SLAVE] ESC ready, chip id=0x%08lX, AL state=0x%02X(%s), code=0x%02X\r\n", + ECAT_LOGI("[ECAT][SLAVE] ESC ready, chip id=0x%08lX, AL state=0x%02X(%s), code=0x%02X\r\n", (unsigned long)s_chipId, (unsigned)s_alState, alStateName, (unsigned)alCode); } @@ -97,7 +97,7 @@ void EthercatSlave::init() s_outputReadIdx = 0U; s_periodicSeq = 0U; s_processedSeq = 0U; - printf("[ECAT][SLAVE] init: %s\r\n", s_escReady ? "OK" : "FAIL(partial)"); + LOG_ERR("[ECAT][SLAVE] init: %s\r\n", s_escReady ? "OK" : "FAIL(partial)"); } __attribute__((section(".ramfunc"), noinline)) diff --git a/GD32E508_DCU_APP/device/CANFD.cpp b/GD32E508_DCU_APP/device/CANFD.cpp index 7b2f96d..26b0f2f 100644 --- a/GD32E508_DCU_APP/device/CANFD.cpp +++ b/GD32E508_DCU_APP/device/CANFD.cpp @@ -209,7 +209,7 @@ void CanFd::initGpio() gpio_afio_port_config(AFIO_PE1_CAN2_CFG, ENABLE); #endif - printf("[CAN-GPIO] AFIO_PCF0=0x%08lX CAN0=PA11/PA12 CAN1=PB12/PB13\r\n", + CAN_LOGI("[CAN-GPIO] AFIO_PCF0=0x%08lX CAN0=PA11/PA12 CAN1=PB12/PB13\r\n", static_cast(AFIO_PCF0)); for(size_t i = 0; i < kChannelCount; ++i) { @@ -322,7 +322,7 @@ bool CanFd::initFdMode(uint32_t canPeriph) /** @brief 打印 SYS/APB1 时钟与目标波特率。 */ void CanFd::printClockInfo() { - printf("[CAN-CLOCK] SYS=%luHz APB1=%luHz nominal=1Mbps data=2Mbps\r\n", + CAN_LOGI("[CAN-CLOCK] SYS=%luHz APB1=%luHz nominal=1Mbps data=2Mbps\r\n", static_cast(SystemCoreClock), static_cast(rcu_clock_freq_get(CK_APB1))); } @@ -360,7 +360,7 @@ void CanFd::initChannelHardware(uint8_t i) if ((CAN_STAT(ch.canPeriph) & CAN_STAT_IWS) == 0U) break; } - printf("[CAN-WARN] CH%u init failed (nom=%u fd=%u STAT=0x%08lX), retry %u/5\r\n", + LOG_ERR("[CAN-WARN] CH%u init failed (nom=%u fd=%u STAT=0x%08lX), retry %u/5\r\n", static_cast(i), nominalOk ? 1U : 0U, fdOk ? 1U : 0U, static_cast(CAN_STAT(ch.canPeriph)), @@ -388,7 +388,7 @@ void CanFd::initChannelHardware(uint8_t i) for (volatile uint32_t d = 0; d < 200000U; ++d) { if ((CAN_STAT(ch.canPeriph) & CAN_STAT_IWS) == 0U) break; } - printf("[CAN-WARN] CH%u needed extra SWRST to exit init mode (STAT=0x%08lX)\r\n", + LOG_ERR("[CAN-WARN] CH%u needed extra SWRST to exit init mode (STAT=0x%08lX)\r\n", static_cast(i), static_cast(CAN_STAT(ch.canPeriph))); } @@ -398,7 +398,7 @@ void CanFd::initChannelHardware(uint8_t i) const uint8_t rxLevelAfter = (gpio_input_bit_get(ch.rxPort, ch.rxPin) != RESET) ? 1U : 0U; const uint32_t tecAfterExit = (errAfterExit >> 16) & 0xFFU; const uint32_t recAfterExit = (errAfterExit >> 24) & 0xFFU; - printf("[CAN-DIAG] CH%u init_nom=%u init_fd=%u exit_ok=%u wait=%lu rx_before=%u rx_after=%u stb=%u STAT=0x%08lX ERR=0x%08lX TEC=%lu REC=%lu\r\n", + CAN_LOGI("[CAN-DIAG] CH%u init_nom=%u init_fd=%u exit_ok=%u wait=%lu rx_before=%u rx_after=%u stb=%u STAT=0x%08lX ERR=0x%08lX TEC=%lu REC=%lu\r\n", static_cast(i), nominalOk ? 1U : 0U, fdOk ? 1U : 0U, @@ -438,7 +438,7 @@ void CanFd::configureAllFilters() if (!kChannelEnabled[i]) continue; configureRxFilter(kChannels[i].canPeriph, kChannels[i].filterNumber, s_mode); } - printf("[CAN] filters configured post-init: HBC1F=%lu FW=0x%08lX\r\n", + CAN_LOGI("[CAN] filters configured post-init: HBC1F=%lu FW=0x%08lX\r\n", static_cast((CAN_FCTL(CAN0) >> 8) & 0x3FU), static_cast(CAN_FW(CAN0))); } @@ -448,14 +448,14 @@ void CanFd::configureAllFilters() void CanFd::printInitResult() { /* ===== 初始化结果汇总 ===== */ - printf("=== CAN INIT RESULT ===\r\n"); + CAN_LOGI("=== CAN INIT RESULT ===\r\n"); for (size_t i = 0; i < kChannelCount; ++i) { const auto &ch = kChannels[i]; uint32_t stat = CAN_STAT(ch.canPeriph); uint32_t bt = CAN_BT(ch.canPeriph); uint32_t dbt = CAN_DBT(ch.canPeriph); bool ok = (stat & CAN_STAT_IWS) == 0U; - printf("CH%u: %s BT=0x%08lX DBT=0x%08lX\r\n", + CAN_LOGI("CH%u: %s BT=0x%08lX DBT=0x%08lX\r\n", static_cast(i), ok ? "OK" : "FAIL(init_mode)", static_cast(bt), @@ -466,7 +466,7 @@ void CanFd::printInitResult() uint32_t fw = CAN_FW(CAN0); uint32_t fw2 = CAN_FW(CAN2); uint32_t hbc = (CAN_FCTL(CAN0) >> 8) & 0x3FU; - printf("FILTER: HBC1F=%lu CAN01_FW=0x%08lX(b0=%lu b2=%lu b14=%lu) CAN2_FW=0x%08lX(b2=%lu)\r\n", + CAN_LOGI("FILTER: HBC1F=%lu CAN01_FW=0x%08lX(b0=%lu b2=%lu b14=%lu) CAN2_FW=0x%08lX(b2=%lu)\r\n", static_cast(hbc), static_cast(fw), static_cast((fw >> 0) & 1U), @@ -481,13 +481,13 @@ void CanFd::printInitResult() void CanFd::printErrorState() { /* ===== 初始化后错误计数器快照(不发帧,避免启动时累积 TEC)===== */ - printf("=== CAN INIT ERR STATE ===\r\n"); + LOG_ERR("=== CAN INIT ERR STATE ===\r\n"); for (size_t i = 0; i < kChannelCount; ++i) { const auto &ch = kChannels[i]; uint32_t err = CAN_ERR(ch.canPeriph); uint32_t tec = (err >> 16) & 0xFFU; uint32_t rec = (err >> 24) & 0xFFU; - printf("CH%u: ERR=0x%08lX TEC=%lu REC=%lu boff=%u epv=%u ew=%u\r\n", + LOG_ERR("CH%u: ERR=0x%08lX TEC=%lu REC=%lu boff=%u epv=%u ew=%u\r\n", static_cast(i), static_cast(err), static_cast(tec), @@ -504,10 +504,10 @@ void CanFd::printErrorState() void CanFd::runSelfTest() { /* ===== Self-test (NORMAL mode, 发到物理总线测 ACK) ===== */ - printf("=== CAN SELF-TEST (normal mode) ===\r\n"); + CAN_LOGI("=== CAN SELF-TEST (normal mode) ===\r\n"); for (size_t i = 0; i < kChannelCount; ++i) { if (!kChannelEnabled[i]) { - printf("CH%u: SKIP(disabled)\r\n", static_cast(i)); + CAN_LOGI("CH%u: SKIP(disabled)\r\n", static_cast(i)); continue; } const uint8_t ch = static_cast(i); @@ -519,14 +519,14 @@ void CanFd::runSelfTest() const CanSelfTestResult fd = runSelfTestFrame(ch, 0x1FFFFF10U | i, data64, 64, true, false); #if (CONFIG_CAN_FD_BRS_ENABLE != 0) const CanSelfTestResult brs = runSelfTestFrame(ch, 0x1FFFFF20U | i, data64, 64, true, true); - printf("CH%u: classic=%s(fd=0) fd_nobrs=%s(fd=1) fd_brs=%s(brs=1) TEC=%lu\r\n", + CAN_LOGI("CH%u: classic=%s(fd=0) fd_nobrs=%s(fd=1) fd_brs=%s(brs=1) TEC=%lu\r\n", static_cast(i), c.tec == 0 ? "ACK" : "NO_ACK", fd.tec == 0 ? "ACK" : "NO_ACK", brs.tec == 0 ? "ACK" : "NO_ACK", static_cast(brs.tec > fd.tec ? brs.tec : fd.tec)); #else - printf("CH%u: classic=%s fd_nobrs=%s TEC=%lu\r\n", + CAN_LOGI("CH%u: classic=%s fd_nobrs=%s TEC=%lu\r\n", static_cast(i), c.tec == 0 ? "ACK" : "NO_ACK", fd.tec == 0 ? "ACK" : "NO_ACK", @@ -542,17 +542,17 @@ void CanFd::runSelfTest() void CanFd::runLoopbackTest() { /* ===== Loopback 回环测试 (内部 TX→RX,不走物理总线) ===== */ - printf("=== CAN LOOPBACK (internal) ===\r\n"); + CAN_LOGI("=== CAN LOOPBACK (internal) ===\r\n"); for (size_t i = 0; i < kChannelCount; ++i) { const auto &ch = kChannels[i]; if (!kChannelEnabled[i]) { - printf("CH%u: SKIP(disabled)\r\n", static_cast(i)); + CAN_LOGI("CH%u: SKIP(disabled)\r\n", static_cast(i)); continue; } if (CAN_STAT(ch.canPeriph) & CAN_STAT_IWS) { - printf("CH%u: SKIP(stuck_init)\r\n", static_cast(i)); + CAN_LOGI("CH%u: SKIP(stuck_init)\r\n", static_cast(i)); continue; } @@ -577,7 +577,7 @@ void CanFd::runLoopbackTest() } if (!lbkmOk) { - printf("CH%u: SKIP(lbk_fail API:%d/%d/%d reg:LCMOD=0)\r\n", + CAN_LOGI("CH%u: SKIP(lbk_fail API:%d/%d/%d reg:LCMOD=0)\r\n", static_cast(i), r1, r2, r3); /* 恢复 normal */ CAN_CTL(ch.canPeriph) |= CAN_CTL_IWMOD; @@ -646,7 +646,7 @@ void CanFd::runLoopbackTest() bool brsOk = (s_channelStats[i].rx_count - rxB3) > 0U; uint32_t tecLb = (CAN_ERR(ch.canPeriph) >> 16) & 0xFFU; - printf("CH%u: classic=%s fd=%s fd_brs=%s TEC=%lu\r\n", + CAN_LOGI("CH%u: classic=%s fd=%s fd_brs=%s TEC=%lu\r\n", static_cast(i), cOk ? "PASS" : "FAIL", fdOk ? "PASS" : "FAIL", @@ -670,7 +670,7 @@ void CanFd::runLoopbackTest() uint32_t tecAfterLb = (errAfterLb >> 16) & 0xFFU; uint32_t recAfterLb = (errAfterLb >> 24) & 0xFFU; uint32_t statAfterLb = CAN_STAT(ch.canPeriph); - printf("CH%u: post-lb TEC=%lu REC=%lu STAT=0x%08lX BT=0x%08lX CTL=0x%08lX\r\n", + CAN_LOGI("CH%u: post-lb TEC=%lu REC=%lu STAT=0x%08lX BT=0x%08lX CTL=0x%08lX\r\n", static_cast(i), static_cast(tecAfterLb), static_cast(recAfterLb), @@ -678,7 +678,7 @@ void CanFd::runLoopbackTest() static_cast(CAN_BT(ch.canPeriph)), static_cast(CAN_CTL(ch.canPeriph))); } - printf("========================\r\n"); + CAN_LOGI("========================\r\n"); } #endif /* CONFIG_CAN_STARTUP_LOOPBACK_TEST_ENABLE */ @@ -687,7 +687,7 @@ void CanFd::runLoopbackTest() void CanFd::dumpRegisters() { /* ===== 初始化后全寄存器快照:诊断 CAN0/CAN1 不收帧 ===== */ - printf("=== POST-INIT FULL REG DUMP ===\r\n"); + CAN_LOGI("=== POST-INIT FULL REG DUMP ===\r\n"); for (size_t i = 0; i < kChannelCount; ++i) { const auto &ch = kChannels[i]; uint32_t ctl = CAN_CTL(ch.canPeriph); @@ -701,7 +701,7 @@ void CanFd::dumpRegisters() uint32_t rfl0 = CAN_RFIFO0(ch.canPeriph) & 0x3U; /* RFL0 bits 1:0 */ bool normalMode = ((stat & CAN_STAT_IWS) == 0U) && ((bt & (3U << 30)) == 0U); - printf("CH%u: %s CTL=0x%08lX STAT=0x%08lX BT=0x%08lX DBT=0x%08lX\r\n" + CAN_LOGI("CH%u: %s CTL=0x%08lX STAT=0x%08lX BT=0x%08lX DBT=0x%08lX\r\n" " ERR=0x%08lX INTEN=0x%08lX FCTL=0x%08lX FW=0x%08lX RFL0=%lu\r\n", static_cast(i), normalMode ? "NORMAL" : "!!!NOT_NORMAL!!!", @@ -716,7 +716,7 @@ void CanFd::dumpRegisters() static_cast(rfl0)); /* 逐位解析关键标志 */ - printf(" IWMOD=%u SLPWMOD=%u ARD=%u ABOR=%u | IWS=%u SLPWS=%u | LCMOD=%u SCMOD=%u\r\n", + CAN_LOGI(" IWMOD=%u SLPWMOD=%u ARD=%u ABOR=%u | IWS=%u SLPWS=%u | LCMOD=%u SCMOD=%u\r\n", (ctl & CAN_CTL_IWMOD) ? 1U : 0U, (ctl & CAN_CTL_SLPWMOD) ? 1U : 0U, /* bit1: sleep mode request */ (ctl & CAN_CTL_ARD) ? 1U : 0U, /* bit4: auto retrans disable */ @@ -726,7 +726,7 @@ void CanFd::dumpRegisters() (bt & (1U << 30)) ? 1U : 0U, /* LCMOD */ (bt & (1U << 31)) ? 1U : 0U); /* SCMOD */ } - printf("===============================\r\n"); + CAN_LOGI("===============================\r\n"); } #endif /* CONFIG_CAN_STARTUP_DIAG_VERBOSE */ @@ -942,7 +942,7 @@ CanFd::CanTxResult CanFd::transmitFrame(uint8_t channelIndex, uint32_t ext_id, /* 诊断:捕获任何通过 transmitFrame 发 0x100 DLC=16 的帧(排查幽灵帧来源) */ if (ext_id == 0x00000100U && dlc == 16U) { - printf("[CAN-DIAG] TX 0x100 DLC=16 via transmitFrame ch=%u\r\n", + CAN_LOGI("[CAN-DIAG] TX 0x100 DLC=16 via transmitFrame ch=%u\r\n", (unsigned)channelIndex); } @@ -1015,7 +1015,7 @@ CanFd::CanTxResult CanFd::transmitFrame(uint8_t channelIndex, uint32_t ext_id, static uint32_t s_lastMailboxLogSeq[kChannelCount] = {0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU}; if (s_lastMailboxLogSeq[channelIndex] != s_feedbackSeq) { const uint32_t errAfter = CAN_ERR(canPeriph); - printf("[CAN-TX-REJECT] CH%u MAILBOX ERR=0x%08lX ERRN=%lu(%s) TEC=%lu REC=%lu TSTAT=0x%08lX\r\n", + LOG_ERR("[CAN-TX-REJECT] CH%u MAILBOX ERR=0x%08lX ERRN=%lu(%s) TEC=%lu REC=%lu TSTAT=0x%08lX\r\n", static_cast(channelIndex), static_cast(errAfter), static_cast((errAfter >> 4U) & 0x07U), @@ -1061,7 +1061,7 @@ void CanFd::setChannelAutoRetrans(uint8_t channelIndex, bool enable) for (volatile uint32_t t = 0U; t < 200000U; ++t) { if ((CAN_STAT(canPeriph) & CAN_STAT_IWS) == 0U) break; } - printf("[CAN] CH%u set auto_retrans=%u -> ARD=%u\r\n", + CAN_LOGI("[CAN] CH%u set auto_retrans=%u -> ARD=%u\r\n", (unsigned)channelIndex, (unsigned)enable, (CAN_CTL(canPeriph) & CAN_CTL_ARD) ? 1U : 0U); } @@ -1369,7 +1369,7 @@ void CanFd::refreshFeedbackSnapshot() * 仅当 TEC/REC 或告警位非零时输出 [CAN-HW-ERR];全量 seq 心跳见 CONFIG_UART_DIAG_LEVEL。 */ if (s_feedbackSeq % 5U == 0U) { #if (CONFIG_UART_DIAG_LEVEL != 0) - printf("[CAN-FB] refresh seq=%lu rx0=%lu rx1=%lu rx2=%lu\r\n", + CAN_LOGI("[CAN-FB] refresh seq=%lu rx0=%lu rx1=%lu rx2=%lu\r\n", (unsigned long)s_feedbackSeq, (unsigned long)s_channelStats[0].rx_count, (unsigned long)s_channelStats[1].rx_count, @@ -1380,7 +1380,7 @@ void CanFd::refreshFeedbackSnapshot() && (hw_err[i] & (CAN_ERR_WERR | CAN_ERR_PERR | CAN_ERR_BOERR)) == 0U) { continue; } - printf("[CAN-HW-ERR] CH%u ERR=0x%08lX ERRN=%lu(%s) TEC=%lu REC=%lu TSTAT=0x%08lX\r\n", + LOG_ERR("[CAN-HW-ERR] CH%u ERR=0x%08lX ERRN=%lu(%s) TEC=%lu REC=%lu TSTAT=0x%08lX\r\n", static_cast(i), static_cast(hw_err[i]), static_cast((hw_err[i] >> 4U) & 0x07U), @@ -1418,7 +1418,7 @@ void CanFd::refreshFeedbackSnapshot() else if (cur & (1U << 3)) stateStr = "BUS_OFF"; else if (cur & (1U << 2)) stateStr = "ERR_PASSIVE"; else if (cur & (1U << 4)) stateStr = "ERR_WARN"; - printf("[CAN-BUS] CH%u: %s -> %s ERR=0x%08lX ERRN=%lu(%s) TEC=%lu REC=%lu seq=%lu\r\n", + LOG_ERR("[CAN-BUS] CH%u: %s -> %s ERR=0x%08lX ERRN=%lu(%s) TEC=%lu REC=%lu seq=%lu\r\n", static_cast(i), (s_prevBusState[i] == 0xFF) ? "?" : (s_prevBusState[i] & (1U << 3)) ? "BUS_OFF" : diff --git a/GD32E508_DCU_APP/main.cpp b/GD32E508_DCU_APP/main.cpp index 51b0ace..06188f7 100644 --- a/GD32E508_DCU_APP/main.cpp +++ b/GD32E508_DCU_APP/main.cpp @@ -19,13 +19,13 @@ */ void App::printBanner() const { - printf("\r\n"); - printf("========================================\r\n"); - printf(" GD32E508 DCU APP started OK\r\n"); - printf(" System clock: 180 MHz\r\n"); - printf(" Build: " __DATE__ " " __TIME__ "\r\n"); - printf("========================================\r\n"); - printf("[APP] APP running, uptime_sec=0\r\n"); + APP_LOGI("\r\n"); + APP_LOGI("========================================\r\n"); + APP_LOGI(" GD32E508 DCU APP started OK\r\n"); + APP_LOGI(" System clock: 180 MHz\r\n"); + APP_LOGI(" Build: " __DATE__ " " __TIME__ "\r\n"); + APP_LOGI("========================================\r\n"); + APP_LOGI("[APP] APP running, uptime_sec=0\r\n"); } /** @@ -37,12 +37,12 @@ void App::printBanner() const */ int App::run() { - printf("[APP] >>> main() entered, SystemCoreClock=%lu\r\n", (unsigned long)SystemCoreClock); - printf("[APP] >>> calling AppInitializer::init()...\r\n"); + APP_LOGI("[APP] >>> main() entered, SystemCoreClock=%lu\r\n", (unsigned long)SystemCoreClock); + APP_LOGI("[APP] >>> calling AppInitializer::init()...\r\n"); AppInitializer::init(); - printf("[APP] >>> init done, calling TaskRunner::init()...\r\n"); + APP_LOGI("[APP] >>> init done, calling TaskRunner::init()...\r\n"); TaskRunner::init(); - printf("[APP] >>> TaskRunner ready, entering main loop\r\n"); + APP_LOGI("[APP] >>> TaskRunner ready, entering main loop\r\n"); printBanner(); while(1) { diff --git a/GD32E508_DCU_APP/sys/config.h b/GD32E508_DCU_APP/sys/config.h index 57719d0..d190dd8 100644 --- a/GD32E508_DCU_APP/sys/config.h +++ b/GD32E508_DCU_APP/sys/config.h @@ -74,13 +74,48 @@ constexpr bool CONFIG_CAN_CH2_ENABLE = false; #define CONFIG_MAIN_LOOP_WFI_ENABLE 0 /** @brief EtherCAT SYNC0 同步模式(#if)。 */ #define CONFIG_ETHERCAT_SYNC_MODE 0 +/** @brief MOTOR-OTA INFO 级日志(握手/进度/流控 chatter);错误与关键事件恒保留。 */ +#define CONFIG_OTA_RELAY_LOG_ENABLE 1 +/** @brief CAN 初始化/自检 INFO 级日志;初始化失败与硬件错误恒保留。 */ +#define CONFIG_CAN_INIT_LOG_ENABLE 1 +/** @brief EtherCAT/EXMC 初始化 INFO 级日志;FAIL 恒保留。 */ +#define CONFIG_ECAT_INIT_LOG_ENABLE 1 +/** @brief 启动横幅与 main 进度打印。 */ +#define CONFIG_APP_BANNER_LOG_ENABLE 1 + +/* ============================================================ + * 日志分级宏:*_LOGI=INFO 级,由上方模块开关编译期裁剪, + * 格式串随之被链接器回收;LOG_ERR=错误/关键事件,恒保留。 + * 使用文件需自行可见 printf 声明()。 + * ============================================================ */ +#define LOG_ERR(...) printf(__VA_ARGS__) +#if CONFIG_OTA_RELAY_LOG_ENABLE +#define OTA_LOGI(...) printf(__VA_ARGS__) +#else +#define OTA_LOGI(...) ((void)0) +#endif +#if CONFIG_CAN_INIT_LOG_ENABLE +#define CAN_LOGI(...) printf(__VA_ARGS__) +#else +#define CAN_LOGI(...) ((void)0) +#endif +#if CONFIG_ECAT_INIT_LOG_ENABLE +#define ECAT_LOGI(...) printf(__VA_ARGS__) +#else +#define ECAT_LOGI(...) ((void)0) +#endif +#if CONFIG_APP_BANNER_LOG_ENABLE +#define APP_LOGI(...) printf(__VA_ARGS__) +#else +#define APP_LOGI(...) ((void)0) +#endif /* ============================================================ * APP 固件版本号 * ============================================================ */ constexpr uint32_t APP_FW_VERSION_MAJOR = 1U; -constexpr uint32_t APP_FW_VERSION_MINOR = 4U; -constexpr uint32_t APP_FW_VERSION_PATCH = 78U; /* 1.4.78:TX错误(MTE)事件驱动快速重发:丢帧后按gap立即补发免等100ms超时,日志加fast=计数 */ +constexpr uint32_t APP_FW_VERSION_MINOR = 5U; +constexpr uint32_t APP_FW_VERSION_PATCH = 0U; /* 1.5.0:大版本:Flash瘦身-34.5%(-fno-rtti/异常+size优化+日志分级宏),启用HardFault诊断,新增尺寸护栏 */ constexpr uint32_t APP_FW_VERSION_BUILD = 0U; diff --git a/GD32E508_DCU_APP/sys/hardfault.cpp b/GD32E508_DCU_APP/sys/hardfault.cpp index f308b11..46d1d74 100644 --- a/GD32E508_DCU_APP/sys/hardfault.cpp +++ b/GD32E508_DCU_APP/sys/hardfault.cpp @@ -138,8 +138,9 @@ extern "C" void HardFault_Handler_C(uint32_t *stack_frame, uint32_t lr_value) { /** * @brief HardFault_Handler 汇编桩——保存栈帧后调用 C 诊断函数。 + * @note 必须 extern "C":否则被 C++ 名字修饰,无法覆盖启动文件的 WEAK 符号。 */ -__attribute__((naked)) void HardFault_Handler(void) { +extern "C" __attribute__((naked)) void HardFault_Handler(void) { __asm volatile( "tst lr, #4 \n" /* 检查 EXC_RETURN 位 2 */ "ite eq \n" diff --git a/GD32E508_DCU_APP/sys/motor_ota_relay.cpp b/GD32E508_DCU_APP/sys/motor_ota_relay.cpp index bf0b3a3..281f3d5 100644 --- a/GD32E508_DCU_APP/sys/motor_ota_relay.cpp +++ b/GD32E508_DCU_APP/sys/motor_ota_relay.cpp @@ -195,7 +195,7 @@ static void keyedCrc32(const uint8_t *key, const uint8_t *data, uint8_t *output) static bool canSend(uint32_t id, const uint8_t *data, uint8_t dlc, bool periodic = false) { /* 诊断:kTransfer 期间只应发 0x101,若出现 0x100 则为幽灵帧 */ if (s_state == State::kTransfer && id == kOtaReqId) { - printf("[MOTOR-OTA] BUG! canSend(0x100) in kTransfer! dlc=%u\r\n", (unsigned)dlc); + LOG_ERR("[MOTOR-OTA] BUG! canSend(0x100) in kTransfer! dlc=%u\r\n", (unsigned)dlc); } const CanFd::CanTxResult r = CanFd::transmitFrame(s_channel, id, data, dlc, periodic); return (r == CanFd::CanTxResult::kOk); @@ -321,7 +321,7 @@ static void sendNonce() { /* 统一重发当前步骤的帧(超时重发 + kHandshakeReq 首发) */ static void sendCurrentStep(uint32_t now_ms) { - printf("[MOTOR-OTA] TX %s try=%u t=%lu\r\n", + OTA_LOGI("[MOTOR-OTA] TX %s try=%u t=%lu\r\n", stepName(s_state), (unsigned)s_retry_count, (unsigned long)now_ms); switch (s_state) { case State::kHandshakeReq: { @@ -413,14 +413,14 @@ static void sendCurrentPacket() { /* 末包 padding 日志在 TX 前打印(sendNextPacket 设 s_last_pad_valid)。 * 用最短格式 + 一次性打印(打印后置 0xFFFF 防重发重复打印)。 */ if (s_last_pad_valid != 0xFFFFU) { - printf("[MOTOR-OTA] PAD v=%u p=%u\r\n", + OTA_LOGI("[MOTOR-OTA] PAD v=%u p=%u\r\n", (unsigned)s_last_pad_valid, (unsigned)(kPacketPayload - s_last_pad_valid)); s_last_pad_valid = 0xFFFFU; } /* 逐包 TX 日志在 5ms 节奏下会拖主循环;仅末包/每 64 包打一行。 */ if (is_last || ((pkt_num & 0x3FU) == 0U)) { - printf("[MOTOR-OTA] TX pkt=%lu/%u%s t=%lu\r\n", + OTA_LOGI("[MOTOR-OTA] TX pkt=%lu/%u%s t=%lu\r\n", (unsigned long)pkt_num, (unsigned)s_total_packets, is_last ? " LAST" : "", (unsigned long)SysTickTimer::getMs()); } @@ -445,7 +445,7 @@ static void sendNextPacket() { static uint32_t s_last_tail_ms = 0; const uint32_t now = SysTickTimer::getMs(); if (now - s_last_tail_ms >= 200U) { - printf("[MOTOR-OTA] 末包欠载,等尾字节 pkt=%u used=%u need=%u fed=%lu t=%lu\r\n", + OTA_LOGI("[MOTOR-OTA] tail-wait pkt=%u used=%u need=%u fed=%lu t=%lu\r\n", (unsigned)s_packets_acked, (unsigned)used, (unsigned)last_valid, (unsigned long)s_fw_fed, (unsigned long)now); @@ -466,7 +466,7 @@ static void sendNextPacket() { static uint32_t s_last_empty_ms = 0; const uint32_t now = SysTickTimer::getMs(); if (now - s_last_empty_ms >= 200U) { - printf("[MOTOR-OTA] 缓冲空,等ESP32喂 pkt=%u used=%u fed=%lu/%lu t=%lu\r\n", + OTA_LOGI("[MOTOR-OTA] buf-empty wait-feed pkt=%u used=%u fed=%lu/%lu t=%lu\r\n", (unsigned)s_packets_acked, (unsigned)used, (unsigned long)s_fw_fed, (unsigned long)s_fw_size, (unsigned long)now); @@ -533,7 +533,7 @@ static void processTransferAck(const uint8_t *data, uint8_t len) { s_crc_resend_pending = true; return; } - printf("[MOTOR-OTA] CRC 重试耗尽 pkt=%u/%u dup=%lu crc=%lu\r\n", + LOG_ERR("[MOTOR-OTA] CRC retry exhausted pkt=%u/%u dup=%lu crc=%lu\r\n", (unsigned)s_packets_acked, (unsigned)s_total_packets, (unsigned long)s_dup_ack_count, (unsigned long)s_crc_err_count); setError(0x23); /* CRC 重试耗尽 */ @@ -543,7 +543,7 @@ static void processTransferAck(const uint8_t *data, uint8_t len) { /* INVALID_HANDSHAKE(0x05):电机 BOOT 已退回 IDLE。按用户要求不再做 * 「发 CANCEL + 从包 0 重握手」的自动重试(会白扔进度、坏总线下反复失败), * 直接中止,由上位机决定是否整体重刷。 */ - printf("[MOTOR-OTA] HANDSHAKE 错误(0x05),中止(不重握手) pkt=%u/%u\r\n", + LOG_ERR("[MOTOR-OTA] HANDSHAKE err(0x05) abort pkt=%u/%u\r\n", (unsigned)s_packets_acked, (unsigned)s_total_packets); setError(0x05); return; @@ -579,7 +579,7 @@ if (next_pkt == 0xFFFFFFFFU) { s_packets_acked = s_total_packets; s_last_acked_pkt = s_total_packets; s_pkt_pending = false; - printf("[MOTOR-OTA] FINISHED pkt=%u/%u dup=%lu crc=%lu resend=%lu fast=%lu t=%lu\r\n", + LOG_ERR("[MOTOR-OTA] FINISHED pkt=%u/%u dup=%lu crc=%lu resend=%lu fast=%lu t=%lu\r\n", (unsigned)s_packets_acked, (unsigned)s_total_packets, (unsigned long)s_dup_ack_count, (unsigned long)s_crc_err_count, (unsigned long)s_ack_resend_total, (unsigned long)s_fast_resend_total, @@ -624,7 +624,7 @@ if (next_pkt == 0xFFFFFFFFU) { * 与 0xD1 喂数抢总线,加重缓冲欠载(CANlog 可见周期性 ~500ms 空洞)。 * 进度由 ESP32 feedTask 按已喂字节估算;终态再 push。 */ if ((s_packets_acked & 0x1F) == 0) { - printf("[MOTOR-OTA] 进度 pkt=%u/%u dup=%lu crc=%lu resend=%lu fast=%lu t=%lu\r\n", + OTA_LOGI("[MOTOR-OTA] progress pkt=%u/%u dup=%lu crc=%lu resend=%lu fast=%lu t=%lu\r\n", (unsigned)s_packets_acked, (unsigned)s_total_packets, (unsigned long)s_dup_ack_count, (unsigned long)s_crc_err_count, (unsigned long)s_ack_resend_total, (unsigned long)s_fast_resend_total, @@ -662,7 +662,7 @@ void onTxTick() { s_retry_count++; s_fast_resend_total++; const uint32_t err = CanFd::readChannelErrorReg(s_channel); - printf("[MOTOR-OTA] TX错快重发 pkt=%u retry=%u tec=%lu rec=%lu errn=%lu\r\n", + LOG_ERR("[MOTOR-OTA] TX-err fast-resend pkt=%u retry=%u tec=%lu rec=%lu errn=%lu\r\n", (unsigned)s_packets_acked, (unsigned)s_retry_count, (unsigned long)((err >> 16) & 0xFFU), (unsigned long)((err >> 24) & 0xFFU), @@ -678,7 +678,7 @@ void onTxTick() { /* 事件时刻 CAN_ERR 快照:钉死丢帧时总线状态(TEC 涨=数据帧发丢, * REC 高=接收方向损坏),摆脱 1Hz [CAN-BUS] 采样混叠。仅日志,不做发送门控。 */ const uint32_t err = CanFd::readChannelErrorReg(s_channel); - printf("[MOTOR-OTA] ACK 超时重发 pkt=%u retry=%u tec=%lu rec=%lu errn=%lu\r\n", + LOG_ERR("[MOTOR-OTA] ACK timeout resend pkt=%u retry=%u tec=%lu rec=%lu errn=%lu\r\n", (unsigned)s_packets_acked, (unsigned)s_retry_count, (unsigned long)((err >> 16) & 0xFFU), (unsigned long)((err >> 24) & 0xFFU), @@ -723,7 +723,7 @@ if (s_pkt_pending) return; /* 当前包待确认,不发新包 if (!is_last && !all_fed && used < water) { static uint32_t s_last_water_ms = 0; if (now - s_last_water_ms >= 200U) { - printf("[MOTOR-OTA] 等SPI水位 used=%u need=%u fed=%lu pkt=%u\r\n", + OTA_LOGI("[MOTOR-OTA] wait-SPI-level used=%u need=%u fed=%lu pkt=%u\r\n", (unsigned)used, (unsigned)water, (unsigned long)s_fw_fed, (unsigned)s_packets_acked); s_last_water_ms = now; @@ -749,12 +749,12 @@ void process() { * 再开始握手就不会被干扰。 */ if (s_state == State::kPreCancel) { if (s_boot_heartbeat_seen && stateTimedOut(kBootSettleMs)) { - printf("[MOTOR-OTA] 0x103 心跳确认 + %ums 残帧窗口已过,开始握手\r\n", + OTA_LOGI("[MOTOR-OTA] 0x103 ok, residue-win %ums passed, handshake\r\n", (unsigned)kBootSettleMs); enterState(State::kHandshakeReq); pushStatus(); } else if (stateTimedOut(kHandshakeTimeoutMs)) { - printf("[MOTOR-OTA] 等待 0x103 超时,电机未进入 BOOT\r\n"); + LOG_ERR("[MOTOR-OTA] wait 0x103 timeout, motor not in BOOT\r\n"); setError(0x02); /* 0x02 = 电机未进入 BOOT */ } return; @@ -785,7 +785,7 @@ void process() { if (rnow - s_last_rxerr_ms >= 200U) { rx_do_log = true; s_last_rxerr_ms = rnow; } } if (rx_do_log) { - printf("[MOTOR-OTA] RX %s pkt=%u/%u len=%u b0=%02X b1=%02X t=%lu\r\n", + OTA_LOGI("[MOTOR-OTA] RX %s pkt=%u/%u len=%u b0=%02X b1=%02X t=%lu\r\n", stepName(s_state), (unsigned)s_packets_acked, (unsigned)s_total_packets, (unsigned)ack_len, (ack_len > 0) ? ack_data[0] : 0xFFU, (ack_len > 1) ? ack_data[1] : 0xFFU, @@ -800,7 +800,7 @@ void process() { enterState(State::kHandshakeNonce); canSend(kOtaReqId, s_nonce, 16); s_last_send_ms = SysTickTimer::getMs(); - printf("[MOTOR-OTA] TX HANDSHAKE_NONCE(0x100:16B) [ACK-driven] t=%lu\r\n", + OTA_LOGI("[MOTOR-OTA] TX HANDSHAKE_NONCE(0x100:16B) [ACK-driven] t=%lu\r\n", (unsigned long)s_last_send_ms); } /* 不匹配的 ACK 靠掉 —— 忽略,等超时重发 REQ */ @@ -809,13 +809,13 @@ void process() { case State::kHandshakeNonce: if (ack_len < 36) { /* 短帧(0x05/干扰) —— 忽略,等真正 48B 或超时重发 */ - printf("[MOTOR-OTA] NONCE ACK 忽略短帧 len=%u b0=0x%02X\r\n", + LOG_ERR("[MOTOR-OTA] NONCE ACK ignore short frame len=%u b0=0x%02X\r\n", (unsigned)ack_len, (ack_len > 0) ? ack_data[0] : 0xFFU); break; } if (memcmp(ack_data + 12, s_nonce + 8, 8) != 0) { /* nonce echo 不匹配 —— 电机收到了错误的帧当 nonce */ - printf("[MOTOR-OTA] NONCE ACK echo mismatch, ignore\r\n"); + LOG_ERR("[MOTOR-OTA] NONCE ACK echo mismatch, ignore\r\n"); break; } /* ✔ nonce 响应正确 —— 派生 K_session,立即发 confirm */ @@ -834,7 +834,7 @@ void process() { aes128_encrypt_block(&s_aes_ctx, plain, confirm); canSend(kOtaReqId, confirm, 16); s_last_send_ms = SysTickTimer::getMs(); - printf("[MOTOR-OTA] TX HANDSHAKE_CONFIRM(0x100:16B) [ACK-driven] t=%lu\r\n", + OTA_LOGI("[MOTOR-OTA] TX HANDSHAKE_CONFIRM(0x100:16B) [ACK-driven] t=%lu\r\n", (unsigned long)s_last_send_ms); } break; @@ -850,7 +850,7 @@ void process() { size_le[3] = static_cast((s_fw_size >> 24) & 0xFF); canSend(kOtaDataId, size_le, 4); s_last_send_ms = SysTickTimer::getMs(); - printf("[MOTOR-OTA] TX ERASE(0x101:fw_size) [ACK-driven] t=%lu\r\n", + OTA_LOGI("[MOTOR-OTA] TX ERASE(0x101:fw_size) [ACK-driven] t=%lu\r\n", (unsigned long)s_last_send_ms); } /* 非 [BA C0] —— 忽略(可能是 0x03/0x05 干扰帧) */ @@ -867,7 +867,7 @@ void process() { * 过时的 0x100 帧 → catch-all → [05] 杀死 OTA。强制 abort 降低风险。 */ CanFd::abortPendingTx(s_channel); s_last_send_ms = SysTickTimer::getMs(); - printf("[MOTOR-OTA] ERASE ACK 收到,等 %ums 再发首包\r\n", + OTA_LOGI("[MOTOR-OTA] ERASE ACK ok, wait %ums then first pkt\r\n", (unsigned)kEraseWaitMs); } /* 非 [BA C0 ...] —— 忽略,等超时重发 fw_size */ @@ -906,7 +906,7 @@ void process() { } else if ((now_ms - s_last_send_ms) >= kStepTimeoutMs) { /* 超时重发 */ if (s_retry_count >= kMaxResends) { - printf("[MOTOR-OTA] %s 未收到应答(已发送 %u 次无响应),中止刷写\r\n", + LOG_ERR("[MOTOR-OTA] %s no-ACK after %u tries, abort\r\n", stepName(s_state), (unsigned)(kMaxResends + 1U)); setError(static_cast(0x30U + static_cast(s_state))); pushStatus(); @@ -989,7 +989,7 @@ s_channel = can_channel; /* 不在 SPI 中断里同步发握手帧(电机跳 BOOT 期间 CAN 可能短暂断开)。 * 先进 kPreCancel 等待电机 0x103 心跳确认已进 BOOT,再由 process() 异步推进到握手。 */ - printf("[MOTOR-OTA] START ch=%u fw=%lu total=%u\r\n", + LOG_ERR("[MOTOR-OTA] START ch=%u fw=%lu total=%u\r\n", (unsigned)can_channel, (unsigned long)fw_size, (unsigned)s_total_packets); s_boot_heartbeat_seen = false; enterState(State::kPreCancel); @@ -1040,7 +1040,7 @@ bool feedData(const uint8_t *data, uint16_t len) { static uint32_t s_last_gap_ms = 0; const uint32_t now = SysTickTimer::getMs(); if (now - s_last_gap_ms >= 200U) { - printf("[MOTOR-OTA] feed 缺口 off=%lu fed=%lu len=%u\r\n", + LOG_ERR("[MOTOR-OTA] feed gap off=%lu fed=%lu len=%u\r\n", (unsigned long)offset, (unsigned long)s_fw_fed, (unsigned)chunk_len); s_last_gap_ms = now; @@ -1061,7 +1061,7 @@ bool feedData(const uint8_t *data, uint16_t len) { void cancel() { if (s_state == State::kIdle) return; - printf("[MOTOR-OTA] CANCEL received in state %s\r\n", stepName(s_state)); + LOG_ERR("[MOTOR-OTA] CANCEL received in state %s\r\n", stepName(s_state)); /* ★ kFinished/kError 时电机已跳转 APP 或已中止,绝不能再发 CAN 取消帧! * kOtaCancelId=0x00000000 与电机 APP 的 CANFD_BOOT_ID(base_id=0x0000) 冲突, * 电机 APP 收到会当作 BOOT 命令 → enter_silent_mode 10s,APP 看似卡死。