feat(spi): 添加ADC反馈命令处理
新增SPI命令类型0xC4用于ADC调试反馈,实现在GD32上采集 温度/VDDA/VIN等模拟量数据的反馈功能,并支持主动推送和被动查询模式。 feat(spi): 扩展PING命令响应格式 修改PING命令响应格式,增加APP身份信息16字节载荷,包含版本号、 启动时间、功能开关位图等信息,用于主机获取从设备详细状态。 refactor(can_feedback): 优化CAN反馈推送逻辑 改进CAN反馈推送机制,跳过编译期关闭的通道,只遍历启用的通道, 确保推送效率并避免无效操作。 feat(comm): 添加EXMC总线初始化和诊断功能 添加了EXMC总线的初始化功能,包括GPIO配置、NOR/SRAM区域参数设置, 以及总线探活机制。实现了总线可见性检测,当检测到全0或全1的挂死状态时 会返回false并输出错误信息。同时添加了printf日志输出用于调试。 refactor(esc_lan9252): 重构ESC初始化返回值 将EscLan9252::init()方法的返回类型从void改为bool, 使其能够返回EXMC总线准备状态,便于上层进行状态检查。 docs(app_spi_cmd_ping): 添加代码注释文档 为SPI命令处理相关类和方法添加详细的Doxygen风格注释文档, 提高代码可读性和维护性。
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* @file app_spi_cmd_adc_feedback.cpp
|
||||
* @brief GD32 ADC 调试反馈(温度 / VDDA / VIN)SPI 命令与 1Hz 主动推送。
|
||||
*
|
||||
* TYPE = SpiDefs::kTypeAdcFeedback (0xC4)
|
||||
*
|
||||
* 总开关:sys/config.h 中 CONFIG_SPI_ADC_FEEDBACK_ENABLE
|
||||
* - 0:不注册 handler、不推送(本文件仍参与链接,函数空实现)
|
||||
* - 1:1Hz 主动 requestEsp32Read(0xC4) + 支持 ESP32 被动查询
|
||||
*
|
||||
* 与 0xC1 CAN 反馈同款模型:主循环 pushStep 非阻塞;ring 未读走则跳过。
|
||||
* 优先级低于 CAN 反馈(runPending 里先 canFeedbackPushStep 再本函数)。
|
||||
*
|
||||
* payload v1 固定 20 字节(小端):
|
||||
* [0] ver=1
|
||||
* [1] flags bit0=sample_valid
|
||||
* [2..3] temp_x100 int16 百分之一摄氏度
|
||||
* [4..5] vdda_mV uint16
|
||||
* [6..7] vin_adc_mV uint16 引脚分压后电压 mV
|
||||
* [8..9] temp_raw uint16
|
||||
* [10..11] vref_raw uint16
|
||||
* [12..15] seq uint32 推送序号
|
||||
* [16..19] uptime_sec uint32
|
||||
*/
|
||||
|
||||
#include "device/spi/spi_command_handler.h"
|
||||
#include "device/spi/app_spi_command.h"
|
||||
#include "device/spi/app_spi_command_defs.h"
|
||||
#include "device/adc.h"
|
||||
#include "sys/config.h"
|
||||
#include "sys/ota_boot_request.h"
|
||||
#include "sys/task_runner.h"
|
||||
#include "main.h"
|
||||
#include <cstring>
|
||||
|
||||
#if (CONFIG_SPI_ADC_FEEDBACK_ENABLE != 0)
|
||||
|
||||
namespace {
|
||||
|
||||
static constexpr uint8_t kPayloadVer = 1U;
|
||||
static constexpr uint16_t kPayloadLen = 20U;
|
||||
|
||||
static uint32_t s_pushSeq = 0U;
|
||||
static volatile bool s_needPush = false;
|
||||
|
||||
/**
|
||||
* @brief 构建 0xC4 ADC 反馈 payload(20B)。
|
||||
* @param[out] out 输出缓冲
|
||||
* @param max_len 缓冲容量
|
||||
* @return 写入长度;失败 0
|
||||
*/
|
||||
static uint16_t buildAdcFeedbackPayload(uint8_t *out, uint16_t max_len)
|
||||
{
|
||||
if (out == nullptr || max_len < kPayloadLen) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
Adc::Sample s{};
|
||||
const bool have = TaskRunner::copyAdcSample(&s);
|
||||
|
||||
const int32_t temp_x100 = have
|
||||
? static_cast<int32_t>(s.temperature * 100.0f)
|
||||
: 0;
|
||||
const uint16_t vdda_mV = have
|
||||
? static_cast<uint16_t>(s.vdda * 1000.0f)
|
||||
: 0U;
|
||||
const uint16_t vin_mV = have
|
||||
? static_cast<uint16_t>(s.vin_adc_v * 1000.0f)
|
||||
: 0U;
|
||||
|
||||
std::memset(out, 0, kPayloadLen);
|
||||
out[0] = kPayloadVer;
|
||||
out[1] = (have && s.valid) ? 0x01U : 0x00U;
|
||||
/* int16 百分之一℃,按两字节小端原样写入 */
|
||||
writeU16Le(&out[2], static_cast<uint16_t>(static_cast<int16_t>(temp_x100)));
|
||||
writeU16Le(&out[4], vdda_mV);
|
||||
writeU16Le(&out[6], vin_mV);
|
||||
writeU16Le(&out[8], have ? s.temp_raw : 0U);
|
||||
writeU16Le(&out[10], have ? s.vref_raw : 0U);
|
||||
writeU32Le(&out[12], s_pushSeq);
|
||||
writeU32Le(&out[16], g_app_uptime_sec);
|
||||
return kPayloadLen;
|
||||
}
|
||||
|
||||
/** @brief SPI 0xC4 ADC 反馈:被动查询应答。 */
|
||||
class SpiAdcFeedbackHandler final : public ISpiCommandHandler {
|
||||
public:
|
||||
/** @brief 是否处理 0xC4。 */
|
||||
bool canHandle(uint8_t frame_type) const override
|
||||
{
|
||||
return frame_type == SpiDefs::kTypeAdcFeedback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 被动查询:回当前 ADC 快照。
|
||||
* @param bus 命令总线
|
||||
* @param ctx 请求上下文
|
||||
*/
|
||||
void handle(AppSpiCommand &bus, const SpiCommandContext &ctx) override
|
||||
{
|
||||
uint8_t payload[kPayloadLen] = {};
|
||||
const uint16_t n = buildAdcFeedbackPayload(payload, sizeof(payload));
|
||||
bus.buildResponse(ctx.tx_buf, ctx.tx_buf_size, ctx.tx_len,
|
||||
SpiDefs::kTypeAdcFeedback, payload, n);
|
||||
}
|
||||
};
|
||||
|
||||
static SpiAdcFeedbackHandler s_handler;
|
||||
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* @brief 标记需要推送一帧 0xC4(由 1Hz taskHeartbeat 调用)。
|
||||
*/
|
||||
void adcFeedbackStartRound()
|
||||
{
|
||||
s_needPush = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 非阻塞推送一步:ring 空闲则 requestEsp32Read(0xC4)。
|
||||
* @note 主循环调用;与 CAN 反馈共用 ring,忙则跳过。
|
||||
*/
|
||||
void adcFeedbackPushStep()
|
||||
{
|
||||
if (!s_needPush) {
|
||||
return;
|
||||
}
|
||||
if (OtaBootRequest::isRebootPending()) {
|
||||
s_needPush = false;
|
||||
return;
|
||||
}
|
||||
/* 与 CAN 反馈共用 ring:未读走则等下一主循环,不抢占 */
|
||||
if (AppSpiCommandBus.isRingPending()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t payload[kPayloadLen] = {};
|
||||
const uint16_t n = buildAdcFeedbackPayload(payload, sizeof(payload));
|
||||
if (n == 0U) {
|
||||
s_needPush = false;
|
||||
return;
|
||||
}
|
||||
|
||||
++s_pushSeq;
|
||||
writeU32Le(&payload[12], s_pushSeq);
|
||||
|
||||
if (AppSpiCommandBus.requestEsp32Read(SpiDefs::kTypeAdcFeedback, payload, n)) {
|
||||
s_needPush = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief 注册 0xC4 处理器。 */
|
||||
void registerSpiAdcFeedbackCommand(AppSpiCommand &bus)
|
||||
{
|
||||
bus.registerHandler(&s_handler);
|
||||
}
|
||||
|
||||
#else /* CONFIG_SPI_ADC_FEEDBACK_ENABLE == 0 */
|
||||
|
||||
/** @brief 开关关闭时的空实现。 */
|
||||
void adcFeedbackStartRound() {}
|
||||
/** @brief 开关关闭时的空实现。 */
|
||||
void adcFeedbackPushStep() {}
|
||||
/** @brief 开关关闭时不注册 handler。 */
|
||||
void registerSpiAdcFeedbackCommand(AppSpiCommand & /*bus*/) {}
|
||||
|
||||
#endif
|
||||
@@ -137,14 +137,21 @@ static uint16_t buildFeedbackPayload(uint8_t channel, uint8_t page,
|
||||
|
||||
namespace {
|
||||
|
||||
/** @brief SPI 0xC1 反馈查询 + 0xC2 模式切换处理器。 */
|
||||
class SpiCanFeedbackHandler final : public ISpiCommandHandler {
|
||||
public:
|
||||
/** @brief 是否处理 0xC1 / 0xC2。 */
|
||||
bool canHandle(uint8_t frame_type) const override
|
||||
{
|
||||
return (frame_type == SpiDefs::kTypeCanFeedback)
|
||||
|| (frame_type == SpiDefs::kTypeCanSetMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 分发到 handleFeedback / handleSetMode。
|
||||
* @param bus 命令总线
|
||||
* @param ctx 请求上下文
|
||||
*/
|
||||
void handle(AppSpiCommand &bus, const SpiCommandContext &ctx) override
|
||||
{
|
||||
if (ctx.frame_type == SpiDefs::kTypeCanFeedback) {
|
||||
@@ -155,6 +162,11 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 被动 0xC1:按 channel/page 回一页反馈。
|
||||
* @param bus 命令总线
|
||||
* @param ctx 请求上下文(payload[0]=ch, [1]=page)
|
||||
*/
|
||||
void handleFeedback(AppSpiCommand &bus, const SpiCommandContext &ctx)
|
||||
{
|
||||
if (ctx.payload_len < 2U) {
|
||||
@@ -180,6 +192,11 @@ private:
|
||||
SpiDefs::kRspAck, payload, payload_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 0xC2:切换三路 CAN 接收过滤模式。
|
||||
* @param bus 命令总线
|
||||
* @param ctx 请求上下文(payload[0]=mode)
|
||||
*/
|
||||
void handleSetMode(AppSpiCommand &bus, const SpiCommandContext &ctx)
|
||||
{
|
||||
if (ctx.payload_len < 1U) {
|
||||
@@ -240,11 +257,18 @@ static SpiCanFeedbackHandler s_handler;
|
||||
*/
|
||||
static volatile bool s_roundActive = true; /* 首次允许启动,无需等 1s */
|
||||
|
||||
/**
|
||||
* @brief 激活新一轮 1Hz CAN 反馈推送(taskHeartbeat 调用)。
|
||||
*/
|
||||
void canFeedbackStartRound()
|
||||
{
|
||||
s_roundActive = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 非阻塞推送一步 0xC1(单页);跳过未使能通道。
|
||||
* @note 主循环调用;ring 忙或本轮未激活则立即返回。
|
||||
*/
|
||||
void canFeedbackPushStep()
|
||||
{
|
||||
static uint8_t s_channel = 0U;
|
||||
@@ -267,6 +291,22 @@ void canFeedbackPushStep()
|
||||
return;
|
||||
}
|
||||
|
||||
/* 跳过编译期关闭的通道(与 APP PING V2_FEAT_CAN_CHx / CONFIG_CAN_CHx_ENABLE 一致) */
|
||||
if (!CanFd::isChannelEnabled(s_channel)) {
|
||||
s_page = 0U;
|
||||
for (;;) {
|
||||
++s_channel;
|
||||
if (s_channel >= kFeedbackChannelCount) {
|
||||
s_channel = 0U;
|
||||
s_roundActive = false;
|
||||
return;
|
||||
}
|
||||
if (CanFd::isChannelEnabled(s_channel)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t payload[kFeedbackPayloadLen] = {};
|
||||
uint16_t payload_len = buildFeedbackPayload(s_channel, s_page,
|
||||
payload, sizeof(payload));
|
||||
@@ -275,17 +315,27 @@ void canFeedbackPushStep()
|
||||
payload, payload_len);
|
||||
}
|
||||
|
||||
/* 推进到下一页/下一通道,循环遍历 3 通道 × 2 页 */
|
||||
/* 推进:每通道 2 页,仅遍历使能通道;到末通道后结束本秒轮次 */
|
||||
if (++s_page >= 2U) {
|
||||
s_page = 0U;
|
||||
if (++s_channel >= kFeedbackChannelCount) {
|
||||
s_channel = 0U;
|
||||
/* 回到 ch=0,page=0:一轮推完,等待下一秒 taskHeartbeat 激活 */
|
||||
s_roundActive = false;
|
||||
for (;;) {
|
||||
++s_channel;
|
||||
if (s_channel >= kFeedbackChannelCount) {
|
||||
s_channel = 0U;
|
||||
s_roundActive = false;
|
||||
break;
|
||||
}
|
||||
if (CanFd::isChannelEnabled(s_channel)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注册 0xC1/0xC2 CAN 反馈与模式切换处理器。
|
||||
* @param bus 命令总线
|
||||
*/
|
||||
void registerSpiCanFeedbackCommand(AppSpiCommand &bus)
|
||||
{
|
||||
bus.registerHandler(&s_handler);
|
||||
|
||||
@@ -5,47 +5,93 @@
|
||||
#include "sys/ota_boot_request.h"
|
||||
#include "sys/systick.h"
|
||||
#include "main.h"
|
||||
#include "spi_link_v2.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* @brief 汇总 GD32 APP 编译期功能开关 → V2_FEAT_* 位图。
|
||||
*/
|
||||
static uint16_t buildAppFeatureFlags()
|
||||
{
|
||||
uint16_t feat = 0U;
|
||||
#if (CONFIG_SPI_ADC_FEEDBACK_ENABLE != 0)
|
||||
feat = static_cast<uint16_t>(feat | V2_FEAT_ADC_FEEDBACK);
|
||||
#endif
|
||||
#if (CONFIG_UART_TEMP_PERIODIC_PRINT != 0)
|
||||
feat = static_cast<uint16_t>(feat | V2_FEAT_UART_TEMP_PRINT);
|
||||
#endif
|
||||
#if (CONFIG_SPI_APP_LOG_ENABLE != 0)
|
||||
feat = static_cast<uint16_t>(feat | V2_FEAT_SPI_APP_LOG);
|
||||
#endif
|
||||
#if (CONFIG_CAN_FD_BRS_ENABLE != 0)
|
||||
feat = static_cast<uint16_t>(feat | V2_FEAT_CAN_BRS);
|
||||
#endif
|
||||
if (CONFIG_CAN_CH0_ENABLE) {
|
||||
feat = static_cast<uint16_t>(feat | V2_FEAT_CAN_CH0);
|
||||
}
|
||||
if (CONFIG_CAN_CH1_ENABLE) {
|
||||
feat = static_cast<uint16_t>(feat | V2_FEAT_CAN_CH1);
|
||||
}
|
||||
if (CONFIG_CAN_CH2_ENABLE) {
|
||||
feat = static_cast<uint16_t>(feat | V2_FEAT_CAN_CH2);
|
||||
}
|
||||
return feat;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* @brief 填充 APP 身份 16B(版本 + feat),供 HELLO_ACK 附加块与 PING 共用。
|
||||
* @param[out] out 至少 V2_APP_IDENTITY_LEN 字节
|
||||
*/
|
||||
void fillGd32AppIdentityPayload(uint8_t *out)
|
||||
{
|
||||
if (out == nullptr) {
|
||||
return;
|
||||
}
|
||||
std::memset(out, 0, V2_APP_IDENTITY_LEN);
|
||||
|
||||
out[0] = (uint8_t)APP_FW_VERSION_MAJOR;
|
||||
out[1] = (uint8_t)APP_FW_VERSION_MINOR;
|
||||
out[2] = (uint8_t)APP_FW_VERSION_PATCH;
|
||||
out[3] = (uint8_t)APP_FW_VERSION_BUILD;
|
||||
|
||||
const BootVersion boot_ver = OtaBootRequest::readBootVersion();
|
||||
out[4] = boot_ver.major;
|
||||
out[5] = boot_ver.minor;
|
||||
out[6] = boot_ver.patch;
|
||||
out[7] = boot_ver.build;
|
||||
|
||||
writeU32Le(&out[8], SysTickTimer::getMs());
|
||||
|
||||
out[12] = V2_FEAT_MAP_VER;
|
||||
writeU16Le(&out[13], buildAppFeatureFlags());
|
||||
/* [15] reserved = 0 */
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/** @brief SPI 0xA1 APP PING 处理器:应答身份 16B。 */
|
||||
class SpiAppPingHandler final : public ISpiCommandHandler {
|
||||
public:
|
||||
/** @brief 是否处理该帧类型。 */
|
||||
bool canHandle(uint8_t frame_type) const override
|
||||
{
|
||||
return frame_type == SpiDefs::kTypeAppPing;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 处理 PING:填充与 HELLO 相同的身份块并回 0x80。
|
||||
* @param bus 命令总线
|
||||
* @param ctx 请求上下文
|
||||
*/
|
||||
void handle(AppSpiCommand &bus, const SpiCommandContext &ctx) override
|
||||
{
|
||||
/* v2 PING 响应 payload(16B):
|
||||
* [0..3] APP version (major/minor/patch/build)
|
||||
* [4..7] BOOT version (major/minor/patch/build)
|
||||
* [8..11] uptime_ms (4B LE)
|
||||
* [12..15] build_hash (4B, 暂用 0 占位) */
|
||||
uint8_t ping_payload[16];
|
||||
std::memset(ping_payload, 0, sizeof(ping_payload));
|
||||
|
||||
ping_payload[0] = (uint8_t)APP_FW_VERSION_MAJOR;
|
||||
ping_payload[1] = (uint8_t)APP_FW_VERSION_MINOR;
|
||||
ping_payload[2] = (uint8_t)APP_FW_VERSION_PATCH;
|
||||
ping_payload[3] = (uint8_t)APP_FW_VERSION_BUILD;
|
||||
|
||||
/* BOOT 版本号从 OTA 配置页 Flash 读取(封装函数,避免裸指针散落) */
|
||||
const BootVersion boot_ver = OtaBootRequest::readBootVersion();
|
||||
ping_payload[4] = boot_ver.major;
|
||||
ping_payload[5] = boot_ver.minor;
|
||||
ping_payload[6] = boot_ver.patch;
|
||||
ping_payload[7] = boot_ver.build;
|
||||
|
||||
const uint32_t uptime_ms = SysTickTimer::getMs();
|
||||
ping_payload[8] = (uint8_t)(uptime_ms & 0xFFU);
|
||||
ping_payload[9] = (uint8_t)((uptime_ms >> 8) & 0xFFU);
|
||||
ping_payload[10] = (uint8_t)((uptime_ms >> 16) & 0xFFU);
|
||||
ping_payload[11] = (uint8_t)((uptime_ms >> 24) & 0xFFU);
|
||||
|
||||
/* build_hash 占位 0(ping_payload[12..15] 已由 memset 清零) */
|
||||
|
||||
/* 与 HELLO_ACK 附加块同一布局,用于存活/uptime 刷新 */
|
||||
uint8_t ping_payload[V2_APP_PING_LEN];
|
||||
fillGd32AppIdentityPayload(ping_payload);
|
||||
bus.buildResponse(ctx.tx_buf, ctx.tx_buf_size, ctx.tx_len,
|
||||
SpiDefs::kRspAck, ping_payload, sizeof(ping_payload));
|
||||
}
|
||||
@@ -55,6 +101,7 @@ static SpiAppPingHandler s_handler;
|
||||
|
||||
} // namespace
|
||||
|
||||
/** @brief 注册 0xA1 PING 命令处理器。 */
|
||||
void registerSpiAppPingCommand(AppSpiCommand &bus)
|
||||
{
|
||||
bus.registerHandler(&s_handler);
|
||||
|
||||
@@ -147,8 +147,9 @@ static bool isFlashRelatedFrame(uint8_t frame_type)
|
||||
}
|
||||
}
|
||||
|
||||
/* GD32 APP 侧同步状态机(ISR 与主循环只读/原子写,避免临界区开销)。 */
|
||||
static volatile uint8_t g_localCredit = 8U;
|
||||
/* GD32 APP 侧 CREDIT:运行时单响应缓冲 0/1(有待发=0,空闲=1)。
|
||||
* 初值必须为 1,禁止用 BOOT 的 8 槽语义;否则 HELLO 前被读到会误导主机 remoteCredit。 */
|
||||
static volatile uint8_t g_localCredit = 1U;
|
||||
|
||||
/* SPI Link v2 会话/序号状态机(ISR 写、主循环读写,均原子,无需临界区)。 */
|
||||
static volatile uint32_t g_sessionId = 0; /* v2 会话 ID(0=未建立) */
|
||||
@@ -384,6 +385,7 @@ extern void registerSpiAppPingCommand(AppSpiCommand &bus);
|
||||
extern void registerSpiCanBridgeCommand(AppSpiCommand &bus);
|
||||
extern void registerSpiCanFeedbackCommand(AppSpiCommand &bus);
|
||||
extern void registerSpiIdSnapshotCommand(AppSpiCommand &bus);
|
||||
extern void registerSpiAdcFeedbackCommand(AppSpiCommand &bus);
|
||||
AppSpiCommand AppSpiCommandBus;
|
||||
void AppSpiCommand::init()
|
||||
{
|
||||
@@ -404,6 +406,7 @@ void AppSpiCommand::init()
|
||||
registerSpiCanBridgeCommand(AppSpiCommandBus);
|
||||
registerSpiCanFeedbackCommand(AppSpiCommandBus);
|
||||
registerSpiIdSnapshotCommand(AppSpiCommandBus);
|
||||
registerSpiAdcFeedbackCommand(AppSpiCommandBus); /* CONFIG 关时为空注册 */
|
||||
|
||||
configureGpio();
|
||||
configureDma();
|
||||
@@ -525,9 +528,13 @@ void AppSpiCommand::processCommand()
|
||||
/* 与 requestEsp32Read() 一致(L5 8bc01dd):建帧前 credit=1,
|
||||
* 避免 TX 占用时 g_localCredit=0 写入 HELLO_ACK,导致主机 remoteCredit=0 拒发 PING。 */
|
||||
g_localCredit = 1U;
|
||||
/* 建连 + 开机身份一次完成:HELLO_ACK = 6B 链路 + 16B 身份(版本/开关) */
|
||||
uint8_t identity[V2_APP_IDENTITY_LEN];
|
||||
fillGd32AppIdentityPayload(identity);
|
||||
size_t built_len = 0U;
|
||||
v2_build_hello_ack_frame(g_sessionId, V2_ROLE_APP, (uint8_t)g_localCredit,
|
||||
0, hdr.tx_seq, m_txBuf, &built_len);
|
||||
0, hdr.tx_seq, identity, sizeof(identity),
|
||||
m_txBuf, &built_len);
|
||||
m_txLen = (uint16_t)built_len;
|
||||
|
||||
s_lastReqSeq = hdr.tx_seq;
|
||||
|
||||
@@ -164,7 +164,22 @@ void canFeedbackPushStep();
|
||||
/** @brief 激活新一轮 CAN 反馈推送(由 1Hz taskHeartbeat 调用)。 */
|
||||
void canFeedbackStartRound();
|
||||
|
||||
/**
|
||||
* @brief ADC 调试反馈(0xC4)主动推送一步。
|
||||
* @note CONFIG_SPI_ADC_FEEDBACK_ENABLE=0 时为空操作。
|
||||
*/
|
||||
void adcFeedbackPushStep();
|
||||
|
||||
/** @brief 激活一次 ADC 调试反馈推送(1Hz taskHeartbeat)。 */
|
||||
void adcFeedbackStartRound();
|
||||
|
||||
/** @brief 全局 SPI 命令总线实例。 */
|
||||
extern AppSpiCommand AppSpiCommandBus;
|
||||
|
||||
/**
|
||||
* @brief 填充 APP 身份 16B(版本 + 功能开关),供 HELLO_ACK 与 PING 共用。
|
||||
* @param out 至少 V2_APP_IDENTITY_LEN 字节。
|
||||
*/
|
||||
void fillGd32AppIdentityPayload(uint8_t *out);
|
||||
|
||||
#endif /* DEVICE_APP_SPI_COMMAND_H */
|
||||
|
||||
@@ -24,6 +24,9 @@ static constexpr uint8_t kTypeCanSend = 0xC0U;
|
||||
static constexpr uint8_t kTypeCanFeedback = 0xC1U; /**< ESP32 -> GD32 轮询 CAN 反馈快照 */
|
||||
static constexpr uint8_t kTypeCanSetMode = 0xC2U; /**< ESP32 -> GD32 切换 CAN 接收过滤模式 */
|
||||
static constexpr uint8_t kTypeIdSnapshot = 0xC3U; /**< ESP32 -> GD32 拉取不重复 ID 快照表 */
|
||||
/** @brief GD32 ADC 调试反馈(温度/VDDA/VIN);1Hz 主动 EVENT 或被动查询。
|
||||
* 由 CONFIG_SPI_ADC_FEEDBACK_ENABLE 门控,调试用可随时关。 */
|
||||
static constexpr uint8_t kTypeAdcFeedback = 0xC4U;
|
||||
|
||||
/* 响应类型 */
|
||||
static constexpr uint8_t kRspAck = 0x80U;
|
||||
@@ -32,6 +35,12 @@ static constexpr uint8_t kRspError = 0x82U;
|
||||
|
||||
} // namespace SpiDefs
|
||||
|
||||
/** @brief 将 16 位值按小端写入 2 字节缓冲。 */
|
||||
inline void writeU16Le(uint8_t *dst, uint16_t val) {
|
||||
dst[0] = static_cast<uint8_t>(val & 0xFFU);
|
||||
dst[1] = static_cast<uint8_t>((val >> 8) & 0xFFU);
|
||||
}
|
||||
|
||||
/** @brief 将 32 位值按小端写入 4 字节缓冲(供 CAN 反馈/ID 快照等 payload 复用)。 */
|
||||
inline void writeU32Le(uint8_t *dst, uint32_t val) {
|
||||
dst[0] = static_cast<uint8_t>(val & 0xFFU);
|
||||
|
||||
Reference in New Issue
Block a user