feat(sys): 添加AES加密和电机OTA中继功能模块
添加了AES128加密算法实现和电机OTA中继相关文件,包括: - ./sys/aes128.h 和 ./sys/aes128.cpp - AES128加密算法头文件和实现 - ./sys/motor_ota_relay.h 和 ./sys/motor_ota_relay.cpp - 电机OTA中继功能 - 更新了项目配置文件包含这些新模块
This commit is contained in:
@@ -8,8 +8,11 @@
|
||||
#include "device/watchdog.h"
|
||||
#include "device/spi/app_spi_command.h"
|
||||
#include "device/canfd.h"
|
||||
#include "device/motor_state.h"
|
||||
#include "device/motor_version.h"
|
||||
#include "sys/config.h"
|
||||
#include "sys/ota_boot_request.h"
|
||||
#include "sys/motor_ota_relay.h"
|
||||
#include "sys/task_manager.h"
|
||||
#include "sys/task_runner.h"
|
||||
#include "comm/ethercat_slave.h"
|
||||
@@ -134,7 +137,7 @@ void TaskRunner::taskAdcProcess()
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行 CAN 周期发送任务:每 1ms 在每个使能通道上发送一帧 CANFD 测试帧。
|
||||
* @brief 执行 CAN 周期发送任务:每 10ms 在每个使能通道上发送一帧 CANFD 测试帧。
|
||||
* @param[in] 无。
|
||||
* @param[out] 无。
|
||||
* @retval 无返回值。
|
||||
@@ -150,6 +153,7 @@ void TaskRunner::taskAdcProcess()
|
||||
*/
|
||||
void TaskRunner::taskCanTxSend()
|
||||
{
|
||||
#if (CONFIG_CAN_PERIODIC_TEST_TX_ENABLE != 0)
|
||||
static uint32_t seq = 0U;
|
||||
|
||||
for (uint8_t ch = 0U; ch < 3U; ++ch) {
|
||||
@@ -176,6 +180,11 @@ void TaskRunner::taskCanTxSend()
|
||||
seq++;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* CONFIG_CAN_PERIODIC_TEST_TX_ENABLE=0:测试帧无业务接收节点 ACK,
|
||||
* 单发模式下会持续产生 MTEn 错误帧,整任务空跑。 */
|
||||
(void)0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -199,6 +208,25 @@ void TaskRunner::taskCanRxParse()
|
||||
OtaBootRequest::process();
|
||||
return;
|
||||
}
|
||||
if(MotorOtaRelay::onCanFrame(s_runtime.last_rx_channel,
|
||||
s_runtime.last_rx_id,
|
||||
s_runtime.last_rx_data,
|
||||
s_runtime.last_rx_len)) {
|
||||
consumed++;
|
||||
continue;
|
||||
}
|
||||
#if (CONFIG_MOTOR_STATE_ENABLE != 0)
|
||||
MotorState::onCanFrame(s_runtime.last_rx_channel,
|
||||
s_runtime.last_rx_id,
|
||||
s_runtime.last_rx_data,
|
||||
s_runtime.last_rx_len);
|
||||
#endif
|
||||
#if (CONFIG_MOTOR_VERSION_ENABLE != 0)
|
||||
MotorVersion::onCanFrame(s_runtime.last_rx_channel,
|
||||
s_runtime.last_rx_id,
|
||||
s_runtime.last_rx_data,
|
||||
s_runtime.last_rx_len);
|
||||
#endif
|
||||
consumed++;
|
||||
}
|
||||
|
||||
@@ -221,6 +249,22 @@ void TaskRunner::taskHeartbeat()
|
||||
canFeedbackStartRound();
|
||||
/* ADC 调试反馈 1Hz:CONFIG_SPI_ADC_FEEDBACK_ENABLE=0 时为空操作 */
|
||||
adcFeedbackStartRound();
|
||||
#if (CONFIG_MOTOR_STATE_ENABLE != 0)
|
||||
MotorState::checkOffline();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 启动多电机状态 0xC5 推送轮次(250ms 独立节拍)。
|
||||
* @note 与 taskHeartbeat 解耦:不连带加速 OTA Boot 轮询 / CAN 快照 / ADC 推送 /
|
||||
* checkOffline 离线判定(3s 阈值)。仅触发本轮 P0/P1 分页推送,
|
||||
* 实际 SPI 传输由 motorStatePushStep() 在主循环按铃协议推进。
|
||||
*/
|
||||
void TaskRunner::taskMotorStatePush()
|
||||
{
|
||||
#if (CONFIG_MOTOR_STATE_ENABLE != 0)
|
||||
motorStateStartRound();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,60 +282,62 @@ bool TaskRunner::copyAdcSample(Adc::Sample *out)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 输出当前温度、电压与 CAN 诊断信息。
|
||||
* @param[in] 无。
|
||||
* @param[out] 无。
|
||||
* @retval 无返回值。
|
||||
* @note 由 5 秒节拍触发,通过 UART 打印当前温度、电压;采用定点整数格式,避免依赖浮点 `printf` 支持。
|
||||
* @brief 5s 诊断任务:默认仅状态变化/错误增量;可选全量 UART 摘要。
|
||||
* @note CONFIG_UART_TEMP_PERIODIC_PRINT=1 时打印 ADC/CAN/ECAT 全量行(调试用)。
|
||||
* 默认=0:相对上次快照有 CAN 错误计数增量、ADC valid 跳变、ECAT ready 变化或 ISR 超阈时才打印。
|
||||
* 采用定点整数格式,避免依赖浮点 printf。
|
||||
*/
|
||||
void TaskRunner::taskDiagnosticPrint()
|
||||
{
|
||||
const auto *diag = CanFd::diag();
|
||||
const auto &s = s_runtime.sample;
|
||||
const int32_t temp_x100 = static_cast<int32_t>(s.temperature * 100.0f);
|
||||
const uint32_t vdda_mV = static_cast<uint32_t>(s.vdda * 1000.0f);
|
||||
const uint32_t vin_adc_mV = static_cast<uint32_t>(s.vin_adc_v * 1000.0f);
|
||||
|
||||
#if (CONFIG_UART_TEMP_PERIODIC_PRINT != 0)
|
||||
/* ---- Debug 全量摘要:周期刷 ADC / CAN 吞吐 / ECAT ISR 统计 ---- */
|
||||
{
|
||||
const int32_t temp_x100 = static_cast<int32_t>(s.temperature * 100.0f);
|
||||
const uint32_t vdda_mV = static_cast<uint32_t>(s.vdda * 1000.0f);
|
||||
const uint32_t vin_adc_mV = static_cast<uint32_t>(s.vin_adc_v * 1000.0f);
|
||||
|
||||
#if (CONFIG_UART_DIAG_LEVEL == 0)
|
||||
printf("[APP] uptime=%lus valid=%u, temp_raw=%u, vref_raw=%u, temp=%ld.%02ld C, vdda=%lu.%03lu V, vin_adc=%lu.%03lu V\r\n",
|
||||
(unsigned long)g_app_uptime_sec,
|
||||
static_cast<unsigned int>(s.valid),
|
||||
static_cast<unsigned int>(s.temp_raw),
|
||||
static_cast<unsigned int>(s.vref_raw),
|
||||
static_cast<long>(temp_x100 / 100),
|
||||
static_cast<long>((temp_x100 >= 0 ? temp_x100 : -temp_x100) % 100),
|
||||
static_cast<unsigned long>(vdda_mV / 1000U),
|
||||
static_cast<unsigned long>(vdda_mV % 1000U),
|
||||
static_cast<unsigned long>(vin_adc_mV / 1000U),
|
||||
static_cast<unsigned long>(vin_adc_mV % 1000U));
|
||||
printf("[APP] uptime=%lus valid=%u, temp_raw=%u, vref_raw=%u, temp=%ld.%02ld C, vdda=%lu.%03lu V, vin_adc=%lu.%03lu V\r\n",
|
||||
(unsigned long)g_app_uptime_sec,
|
||||
static_cast<unsigned int>(s.valid),
|
||||
static_cast<unsigned int>(s.temp_raw),
|
||||
static_cast<unsigned int>(s.vref_raw),
|
||||
static_cast<long>(temp_x100 / 100),
|
||||
static_cast<long>((temp_x100 >= 0 ? temp_x100 : -temp_x100) % 100),
|
||||
static_cast<unsigned long>(vdda_mV / 1000U),
|
||||
static_cast<unsigned long>(vdda_mV % 1000U),
|
||||
static_cast<unsigned long>(vin_adc_mV / 1000U),
|
||||
static_cast<unsigned long>(vin_adc_mV % 1000U));
|
||||
#else
|
||||
printf("[APP] uptime=%lus valid=%u, temp=%ld.%02ld C, vdda=%lu.%03lu V, vin_adc=%lu.%03lu V, rx_ch=%u, rx_id=0x%08lX, rx_len=%u, tx_ch=%u, can_tx=%lu, can_rx=%lu, sw_drop=%lu, hw_full=%lu, hw_over=%lu, tx_abort=%lu, can_err=%lu\r\n",
|
||||
(unsigned long)g_app_uptime_sec,
|
||||
static_cast<unsigned int>(s.valid),
|
||||
static_cast<long>(temp_x100 / 100),
|
||||
static_cast<long>((temp_x100 >= 0 ? temp_x100 : -temp_x100) % 100),
|
||||
static_cast<unsigned long>(vdda_mV / 1000U),
|
||||
static_cast<unsigned long>(vdda_mV % 1000U),
|
||||
static_cast<unsigned long>(vin_adc_mV / 1000U),
|
||||
static_cast<unsigned long>(vin_adc_mV % 1000U),
|
||||
static_cast<unsigned int>(s_runtime.last_rx_channel),
|
||||
static_cast<unsigned long>(s_runtime.last_rx_id),
|
||||
static_cast<unsigned int>(s_runtime.last_rx_len),
|
||||
static_cast<unsigned int>(diag->last_tx_channel),
|
||||
static_cast<unsigned long>(diag->tx_count),
|
||||
static_cast<unsigned long>(diag->rx_count),
|
||||
static_cast<unsigned long>(diag->rx_drop_count),
|
||||
static_cast<unsigned long>(diag->rx_fifo_full_count),
|
||||
static_cast<unsigned long>(diag->rx_fifo_overfull_count),
|
||||
static_cast<unsigned long>(diag->tx_abort_count),
|
||||
static_cast<unsigned long>(diag->error_count));
|
||||
printf("[APP] uptime=%lus valid=%u, temp=%ld.%02ld C, vdda=%lu.%03lu V, vin_adc=%lu.%03lu V, rx_ch=%u, rx_id=0x%08lX, rx_len=%u, tx_ch=%u, can_tx=%lu, can_rx=%lu, sw_drop=%lu, hw_full=%lu, hw_over=%lu, tx_abort=%lu, can_err=%lu\r\n",
|
||||
(unsigned long)g_app_uptime_sec,
|
||||
static_cast<unsigned int>(s.valid),
|
||||
static_cast<long>(temp_x100 / 100),
|
||||
static_cast<long>((temp_x100 >= 0 ? temp_x100 : -temp_x100) % 100),
|
||||
static_cast<unsigned long>(vdda_mV / 1000U),
|
||||
static_cast<unsigned long>(vdda_mV % 1000U),
|
||||
static_cast<unsigned long>(vin_adc_mV / 1000U),
|
||||
static_cast<unsigned long>(vin_adc_mV % 1000U),
|
||||
static_cast<unsigned int>(s_runtime.last_rx_channel),
|
||||
static_cast<unsigned long>(s_runtime.last_rx_id),
|
||||
static_cast<unsigned int>(s_runtime.last_rx_len),
|
||||
static_cast<unsigned int>(diag->last_tx_channel),
|
||||
static_cast<unsigned long>(diag->tx_count),
|
||||
static_cast<unsigned long>(diag->rx_count),
|
||||
static_cast<unsigned long>(diag->rx_drop_count),
|
||||
static_cast<unsigned long>(diag->rx_fifo_full_count),
|
||||
static_cast<unsigned long>(diag->rx_fifo_overfull_count),
|
||||
static_cast<unsigned long>(diag->tx_abort_count),
|
||||
static_cast<unsigned long>(diag->error_count));
|
||||
#endif
|
||||
|
||||
{
|
||||
if (EthercatSlave::isEscReady()) {
|
||||
uint32_t maxCyc = 0U, avgCyc = 0U, cnt = 0U;
|
||||
EthercatSlave::getIsrStats(&maxCyc, &avgCyc, &cnt);
|
||||
/* 180MHz: cycles / 180 = µs;用 *1000/180 获得毫微秒精度避免浮点 */
|
||||
/* 180MHz: cycles / 180 = µs;用 *1000/180 获得亚微秒精度避免浮点 */
|
||||
const uint32_t maxUs_x1000 = maxCyc * 1000U / 180U;
|
||||
const uint32_t avgUs_x1000 = avgCyc * 1000U / 180U;
|
||||
printf("[ECAT] periodicIsr cnt=%lu max=%lu.%03luus avg=%lu.%03luus\r\n",
|
||||
@@ -303,6 +349,88 @@ void TaskRunner::taskDiagnosticPrint()
|
||||
(unsigned long)EthercatSlave::getChipId());
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* ---- 默认静默路径:仅错误增量 / 状态变化,无 uptime 心跳 ---- */
|
||||
{
|
||||
static uint32_t s_prev_rx_drop = 0U;
|
||||
static uint32_t s_prev_rx_fifo_full = 0U;
|
||||
static uint32_t s_prev_rx_fifo_overfull = 0U;
|
||||
static uint32_t s_prev_tx_abort = 0U;
|
||||
static uint32_t s_prev_error = 0U;
|
||||
static uint8_t s_prev_adc_valid = 0xFFU; /* 0xFF=尚未采样 */
|
||||
static bool s_prev_esc_ready = false;
|
||||
static bool s_esc_ready_inited = false;
|
||||
static uint32_t s_prev_ecat_max_cyc = 0U;
|
||||
|
||||
const uint32_t rx_drop = diag->rx_drop_count;
|
||||
const uint32_t rx_full = diag->rx_fifo_full_count;
|
||||
const uint32_t rx_over = diag->rx_fifo_overfull_count;
|
||||
const uint32_t tx_abort = diag->tx_abort_count;
|
||||
const uint32_t can_err = diag->error_count;
|
||||
|
||||
if (rx_drop > s_prev_rx_drop || rx_full > s_prev_rx_fifo_full
|
||||
|| rx_over > s_prev_rx_fifo_overfull || tx_abort > s_prev_tx_abort
|
||||
|| can_err > s_prev_error) {
|
||||
printf("[CAN-DIAG] uptime=%lus err=%lu(+%lu) drop=%lu(+%lu) full=%lu(+%lu) over=%lu(+%lu) abort=%lu(+%lu)\r\n",
|
||||
(unsigned long)g_app_uptime_sec,
|
||||
(unsigned long)can_err,
|
||||
(unsigned long)(can_err - s_prev_error),
|
||||
(unsigned long)rx_drop,
|
||||
(unsigned long)(rx_drop - s_prev_rx_drop),
|
||||
(unsigned long)rx_full,
|
||||
(unsigned long)(rx_full - s_prev_rx_fifo_full),
|
||||
(unsigned long)rx_over,
|
||||
(unsigned long)(rx_over - s_prev_rx_fifo_overfull),
|
||||
(unsigned long)tx_abort,
|
||||
(unsigned long)(tx_abort - s_prev_tx_abort));
|
||||
s_prev_rx_drop = rx_drop;
|
||||
s_prev_rx_fifo_full = rx_full;
|
||||
s_prev_rx_fifo_overfull = rx_over;
|
||||
s_prev_tx_abort = tx_abort;
|
||||
s_prev_error = can_err;
|
||||
}
|
||||
|
||||
if (s_prev_adc_valid == 0xFFU) {
|
||||
s_prev_adc_valid = s.valid;
|
||||
} else if (s.valid != s_prev_adc_valid) {
|
||||
printf("[APP] adc valid %u -> %u (uptime=%lus)\r\n",
|
||||
static_cast<unsigned int>(s_prev_adc_valid),
|
||||
static_cast<unsigned int>(s.valid),
|
||||
(unsigned long)g_app_uptime_sec);
|
||||
s_prev_adc_valid = s.valid;
|
||||
}
|
||||
|
||||
const bool esc_ready = EthercatSlave::isEscReady();
|
||||
if (!s_esc_ready_inited) {
|
||||
s_prev_esc_ready = esc_ready;
|
||||
s_esc_ready_inited = true;
|
||||
} else if (esc_ready != s_prev_esc_ready) {
|
||||
printf("[ECAT] ESC ready %u -> %u chip_id=0x%08lX (uptime=%lus)\r\n",
|
||||
static_cast<unsigned int>(s_prev_esc_ready ? 1U : 0U),
|
||||
static_cast<unsigned int>(esc_ready ? 1U : 0U),
|
||||
(unsigned long)EthercatSlave::getChipId(),
|
||||
(unsigned long)g_app_uptime_sec);
|
||||
s_prev_esc_ready = esc_ready;
|
||||
}
|
||||
|
||||
if (esc_ready) {
|
||||
uint32_t maxCyc = 0U, avgCyc = 0U, cnt = 0U;
|
||||
EthercatSlave::getIsrStats(&maxCyc, &avgCyc, &cnt);
|
||||
/* 阈值单位 µs → CPU 周期(180 MHz) */
|
||||
const uint32_t threshCyc = CONFIG_ETHERCAT_ISR_MAX_US_THRESHOLD * 180U;
|
||||
if (maxCyc > threshCyc && maxCyc > s_prev_ecat_max_cyc) {
|
||||
const uint32_t maxUs_x1000 = maxCyc * 1000U / 180U;
|
||||
printf("[ECAT] ISR max over threshold: max=%lu.%03luus thr=%luus cnt=%lu (uptime=%lus)\r\n",
|
||||
(unsigned long)(maxUs_x1000 / 1000U),
|
||||
(unsigned long)(maxUs_x1000 % 1000U),
|
||||
(unsigned long)CONFIG_ETHERCAT_ISR_MAX_US_THRESHOLD,
|
||||
(unsigned long)cnt,
|
||||
(unsigned long)g_app_uptime_sec);
|
||||
s_prev_ecat_max_cyc = maxCyc;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -359,12 +487,23 @@ void TaskRunner::runPending()
|
||||
OtaBootRequest::process();
|
||||
}
|
||||
|
||||
/* 电机 OTA relay:活跃时每圈推进状态机(等 ACK / 超时 / 发下一包)。
|
||||
* 非活跃时立即返回,开销可忽略。 */
|
||||
MotorOtaRelay::process();
|
||||
/* 数据发送推进:主循环每圈调用,按 SysTick 钟表控制每包间隔
|
||||
* (替代原靠 tick100us 计数 + TASK_MOTOR_OTA_TX 的方式,消除计数器竞争)。 */
|
||||
MotorOtaRelay::onTxTick();
|
||||
|
||||
/* CAN 反馈主动推送:GD32 APP 循环推送 3 通道 × 2 页反馈帧到 ESP32,
|
||||
* 替代 ESP32 主动轮询。非阻塞:上一帧未读走时立即返回。
|
||||
* 每次主循环迭代调用一次,ESP32 读走一帧后 CS 释放中断唤醒主循环继续推送。 */
|
||||
canFeedbackPushStep();
|
||||
/* 多电机状态(0xC5):优先级介于 CAN 反馈与 ADC 之间;ring 忙则跳过。 */
|
||||
motorStatePushStep();
|
||||
/* ADC 调试反馈(0xC4):优先级低于 CAN;ring 忙则跳过。可 config 关闭。 */
|
||||
adcFeedbackPushStep();
|
||||
/* 多电机版本(0xC6):事件驱动、低频,优先级最低;无 dirty 版本时立即返回。 */
|
||||
motorVersionPushStep();
|
||||
|
||||
/* 周期路径( SYNC0 ISR preempt=0 )用 s_periodicSeq 序列号通知主循环,
|
||||
* 不再走 task_flags,避免 BASEPRI 临界区与 preempt=0 的 RMW 竞态。
|
||||
@@ -385,6 +524,7 @@ void TaskRunner::runPending()
|
||||
if(pending & (1UL << TASK_CAN_RX_PARSE)) taskCanRxParse();
|
||||
if(pending & (1UL << TASK_CAN_TX_SEND)) taskCanTxSend();
|
||||
if(pending & (1UL << TASK_HEARTBEAT)) taskHeartbeat();
|
||||
if(pending & (1UL << TASK_MOTOR_STATE_PUSH)) taskMotorStatePush();
|
||||
if(pending & (1UL << TASK_DIAGNOSTIC_PRINT)) taskDiagnosticPrint();
|
||||
if(pending & (1UL << TASK_ETHERCAT_PROCESS)) taskEthercatProcess();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user