feat(canfd): 添加直接发送CANFD帧功能用于SPI桥接场景

- 新增 CanFd::transmitFrame() 方法,支持绕过软件队列直接调用
  硬件发送CANFD扩展帧
- 实现参数验证,包括通道索引、数据指针和DLC长度检查
- 集成GD32E508特定的FD标志和波特率切换设置
- 更新诊断统计信息,记录发送计数、最后ID、通道和负载长度

feat(spi-command): 添加SPI到CAN总线桥接发送命令类型

- 引入 kTypeCanSend (0xC0) 命令类型用于SPI-CAN桥接
- 实现CAN_SEND命令处理逻辑,解析载荷中的通道、ID和数据
- 支持3个CAN通道(0/1/2),验证通道有效性防止越界访问
- 添加详细的错误处理和日志记录机制

refactor(config): 更新SPI命令ACK确认码和构建版本号

- 将CONFIG_SPI_APP_OTA_BOOT_ACK_OK从0xA5U改为0xB5U以避免冲突
- 提升APP_FW_VERSION_BUILD从1到2以反映新功能集成
This commit is contained in:
cbb
2026-06-13 17:07:25 +08:00
parent d0b6d9537e
commit 01382a3fc1
5 changed files with 100 additions and 57 deletions
@@ -12,6 +12,7 @@
*/
#include "device/app_spi_command.h"
#include "device/canfd.h"
extern "C" {
#include "gd32e50x_exti.h"
@@ -34,6 +35,7 @@ extern "C" {
* ============================================================ */
static constexpr uint8_t kSof = 0xA5U;
static constexpr uint8_t kTypeBootReq = 0xB0U;
static constexpr uint8_t kTypeCanSend = 0xC0U;
static constexpr uint8_t kTypeOtaReq = 0x01U;
static constexpr uint8_t kTypeAppPing = 0xA1U;
static constexpr uint8_t kTypeOtaData = 0x02U;
@@ -359,6 +361,47 @@ void AppSpiCommand::processCommand()
spi_build_frame(kRspError, &err, 1U, s_txBuf, &tx_len);
}
break;
case kTypeCanSend:
/* SPI→CAN 桥接:解析载荷并通过 CanFd 直接发送到 CAN 总线
*
* payload 布局 (6~69B):
* [0] = channel (0/1/2)
* [1..4] = ext_id (32-bit Big-Endian)
* [5..] = CAN data (1~64 bytes, 实际长度 = payload_len - 5)
*/
if (payload_len < 6U) {
/* 载荷太短:至少需要 1B channel + 4B ext_id + 1B data */
logDeferred("[SPI-APP] CAN_SEND 载荷太短 → ERROR");
uint8_t err = 0xE0U;
spi_build_frame(kRspError, &err, 1U, s_txBuf, &tx_len);
} else {
uint8_t can_ch = payload[0];
uint32_t can_id = (static_cast<uint32_t>(payload[1]) << 24)
| (static_cast<uint32_t>(payload[2]) << 16)
| (static_cast<uint32_t>(payload[3]) << 8)
| static_cast<uint32_t>(payload[4]);
const uint8_t *can_data = &payload[5];
uint8_t can_dlc = static_cast<uint8_t>(payload_len - 5U);
if (can_ch >= 3U) {
logDeferredFmt("[SPI-APP] CAN_SEND 通道非法: CH%d → ERROR", can_ch);
uint8_t err = 0xE1U;
spi_build_frame(kRspError, &err, 1U, s_txBuf, &tx_len);
} else {
bool ok = CanFd::transmitFrame(can_ch, can_id, can_data, can_dlc);
if (ok) {
logDeferredFmt("[SPI-APP] CAN_SEND CH%d → OK", can_ch);
uint8_t ack = 0x00U; /* 成功 */
spi_build_frame(kRspAck, &ack, 1U, s_txBuf, &tx_len);
} else {
logDeferredFmt("[SPI-APP] CAN_SEND CH%d FIFO满 → ERROR", can_ch);
uint8_t err = 0xE2U; /* FIFO 满 */
spi_build_frame(kRspError, &err, 1U, s_txBuf, &tx_len);
}
}
}
break;
}
s_txLen = (uint8_t)tx_len;
s_txPos = 0U;