feat(build): 优化构建配置并引入日志分级系统
- 将优化级别从balanced调整为size,减少Flash占用 - 添加hardfault.cpp文件以增强故障诊断能力 - 关闭RTTI和异常处理以移除libcppabi运行时(节省约2.5KB Flash) - 添加链接器参数输出未引用段与总量报告用于Flash尺寸分析 refactor(logging): 统一日志输出并实现编译时日志分级 - 将printf调用替换为模块化的日志宏(ECAT_LOGI、CAN_LOGI等) - 实现CONFIG_*_LOG_ENABLE编译开关控制各模块INFO级日志 - 错误和关键事件使用LOG_ERR恒定保留,其他日志可编译时裁剪 - 保持原有日志内容不变,但支持链接器自动回收未使用的格式字符串
This commit is contained in:
@@ -44,7 +44,7 @@ solution:
|
||||
|
||||
- type: Release
|
||||
debug: off
|
||||
optimize: balanced
|
||||
optimize: size
|
||||
|
||||
# List related projects.
|
||||
projects:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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<unsigned long>(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<unsigned long>(SystemCoreClock),
|
||||
static_cast<unsigned long>(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<unsigned>(i),
|
||||
nominalOk ? 1U : 0U, fdOk ? 1U : 0U,
|
||||
static_cast<unsigned long>(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<unsigned>(i),
|
||||
static_cast<unsigned long>(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<unsigned>(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<unsigned long>((CAN_FCTL(CAN0) >> 8) & 0x3FU),
|
||||
static_cast<unsigned long>(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<unsigned>(i),
|
||||
ok ? "OK" : "FAIL(init_mode)",
|
||||
static_cast<unsigned long>(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<unsigned long>(hbc),
|
||||
static_cast<unsigned long>(fw),
|
||||
static_cast<unsigned long>((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<unsigned>(i),
|
||||
static_cast<unsigned long>(err),
|
||||
static_cast<unsigned long>(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<unsigned>(i));
|
||||
CAN_LOGI("CH%u: SKIP(disabled)\r\n", static_cast<unsigned>(i));
|
||||
continue;
|
||||
}
|
||||
const uint8_t ch = static_cast<uint8_t>(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<unsigned>(i),
|
||||
c.tec == 0 ? "ACK" : "NO_ACK",
|
||||
fd.tec == 0 ? "ACK" : "NO_ACK",
|
||||
brs.tec == 0 ? "ACK" : "NO_ACK",
|
||||
static_cast<unsigned long>(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<unsigned>(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<unsigned>(i));
|
||||
CAN_LOGI("CH%u: SKIP(disabled)\r\n", static_cast<unsigned>(i));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CAN_STAT(ch.canPeriph) & CAN_STAT_IWS) {
|
||||
printf("CH%u: SKIP(stuck_init)\r\n", static_cast<unsigned>(i));
|
||||
CAN_LOGI("CH%u: SKIP(stuck_init)\r\n", static_cast<unsigned>(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<unsigned>(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<unsigned>(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<unsigned>(i),
|
||||
static_cast<unsigned long>(tecAfterLb),
|
||||
static_cast<unsigned long>(recAfterLb),
|
||||
@@ -678,7 +678,7 @@ void CanFd::runLoopbackTest()
|
||||
static_cast<unsigned long>(CAN_BT(ch.canPeriph)),
|
||||
static_cast<unsigned long>(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<unsigned>(i),
|
||||
normalMode ? "NORMAL" : "!!!NOT_NORMAL!!!",
|
||||
@@ -716,7 +716,7 @@ void CanFd::dumpRegisters()
|
||||
static_cast<unsigned long>(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<unsigned>(channelIndex),
|
||||
static_cast<unsigned long>(errAfter),
|
||||
static_cast<unsigned long>((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<unsigned>(i),
|
||||
static_cast<unsigned long>(hw_err[i]),
|
||||
static_cast<unsigned long>((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<unsigned>(i),
|
||||
(s_prevBusState[i] == 0xFF) ? "?" :
|
||||
(s_prevBusState[i] & (1U << 3)) ? "BUS_OFF" :
|
||||
|
||||
+11
-11
@@ -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) {
|
||||
|
||||
@@ -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 声明(<cstdio>)。
|
||||
* ============================================================ */
|
||||
#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;
|
||||
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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<uint8_t>((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<uint8_t>(0x30U + static_cast<uint8_t>(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 看似卡死。
|
||||
|
||||
Reference in New Issue
Block a user