2026-05-10 17:28:14 +08:00
|
|
|
/**
|
|
|
|
|
* @file task_runner.cpp
|
|
|
|
|
* @brief 任务执行器实现。
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "main.h"
|
|
|
|
|
#include "device/adc.h"
|
|
|
|
|
#include "device/canfd.h"
|
|
|
|
|
#include "device/temp_sensor.h"
|
2026-05-10 21:27:51 +08:00
|
|
|
#include "sys/config.h"
|
2026-05-10 17:28:14 +08:00
|
|
|
#include "sys/task_manager.h"
|
|
|
|
|
#include "sys/task_runner.h"
|
|
|
|
|
|
|
|
|
|
struct TaskRunner::Runtime {
|
|
|
|
|
temp_sensor_data_t sample{};
|
2026-05-10 21:27:51 +08:00
|
|
|
uint8_t last_rx_channel = 0U;
|
|
|
|
|
uint32_t last_rx_id = 0U;
|
|
|
|
|
uint8_t last_rx_len = 0U;
|
|
|
|
|
uint8_t last_rx_data[64] = {0};
|
2026-05-10 17:28:14 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TaskRunner::Runtime TaskRunner::s_runtime;
|
|
|
|
|
|
2026-05-10 21:27:51 +08:00
|
|
|
/**
|
|
|
|
|
* @brief 采样 VIN 与 VREF 原始 ADC 数值。
|
|
|
|
|
* @param[in] 无。
|
|
|
|
|
* @param[out] 无。
|
|
|
|
|
* @retval 无返回值。
|
|
|
|
|
* @note 从 ADC DMA 缓冲中读取外部 VIN_ADC 与内部 VREFINT 通道最新值。
|
|
|
|
|
*/
|
2026-05-10 17:28:14 +08:00
|
|
|
void TaskRunner::taskAdcVrefSample()
|
|
|
|
|
{
|
2026-05-10 21:27:51 +08:00
|
|
|
Adc::collectSample(&s_runtime.sample);
|
2026-05-10 17:28:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-10 21:27:51 +08:00
|
|
|
/**
|
|
|
|
|
* @brief 采样内部温度通道原始 ADC 数值。
|
|
|
|
|
* @param[in] 无。
|
|
|
|
|
* @param[out] 无。
|
|
|
|
|
* @retval 无返回值。
|
|
|
|
|
* @note 读取 ADC DMA 缓冲中的内部温度通道最新值。
|
|
|
|
|
*/
|
2026-05-10 17:28:14 +08:00
|
|
|
void TaskRunner::taskAdcTempSample()
|
|
|
|
|
{
|
2026-05-10 21:27:51 +08:00
|
|
|
Adc::collectSample(&s_runtime.sample);
|
2026-05-10 17:28:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-10 21:27:51 +08:00
|
|
|
/**
|
|
|
|
|
* @brief 根据原始采样值计算工程量结果。
|
|
|
|
|
* @param[in] 无。
|
|
|
|
|
* @param[out] 无。
|
|
|
|
|
* @retval 无返回值。
|
|
|
|
|
* @note 输出 `vin_adc_v`、`vdda` 和 `temperature` 等可直接使用的工程值。
|
|
|
|
|
*/
|
2026-05-10 17:28:14 +08:00
|
|
|
void TaskRunner::taskAdcProcess()
|
|
|
|
|
{
|
2026-05-10 21:27:51 +08:00
|
|
|
/* 当前采样任务已直接调用 Adc::collectSample() 填充工程值。
|
|
|
|
|
* 该处理任务保留为调度兼容入口,后续若重新拆分采样/换算阶段,可在此恢复。 */
|
|
|
|
|
(void)s_runtime.sample;
|
2026-05-10 17:28:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-10 21:27:51 +08:00
|
|
|
/**
|
|
|
|
|
* @brief 执行兼容保留的 CAN 接收轮询任务。
|
|
|
|
|
* @param[in] 无。
|
|
|
|
|
* @param[out] 无。
|
|
|
|
|
* @retval 无返回值。
|
|
|
|
|
* @note 当前三路 CANFD 接收已由 RX0 中断驱动,该任务仅保留接口兼容性。
|
|
|
|
|
*/
|
2026-05-10 17:28:14 +08:00
|
|
|
void TaskRunner::taskCanRxPoll() { CanFd::poll(); }
|
|
|
|
|
|
2026-05-10 21:27:51 +08:00
|
|
|
/**
|
|
|
|
|
* @brief 执行预留的 CAN 发送执行任务。
|
|
|
|
|
* @param[in] 无。
|
|
|
|
|
* @param[out] 无。
|
|
|
|
|
* @retval 无返回值。
|
|
|
|
|
* @note 当前阶段不做周期性发送调度;若后续需要显式验证某一路发送能力,可由调用方先 prepare,再直接调用 `CanFd::sendPrepared()`。
|
|
|
|
|
*/
|
|
|
|
|
void TaskRunner::taskCanTxSend()
|
|
|
|
|
{
|
|
|
|
|
/* 当前阶段不做周期性发送调度。
|
|
|
|
|
* 若后续需要显式验证某一路发送能力,可由调用方先 prepare,再直接调用 CanFd::sendPrepared()。 */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 解析并消费一帧待处理的 CAN 接收报文。
|
|
|
|
|
* @param[in] 无。
|
|
|
|
|
* @param[out] 无。
|
|
|
|
|
* @retval 无返回值。
|
|
|
|
|
* @note 若当前存在待消费报文,则更新最近一次接收的 ID、数据长度、数据内容与来源通道号。
|
|
|
|
|
*/
|
2026-05-10 17:28:14 +08:00
|
|
|
void TaskRunner::taskCanRxParse()
|
|
|
|
|
{
|
|
|
|
|
if(CanFd::hasRxFrame())
|
2026-05-10 21:27:51 +08:00
|
|
|
CanFd::consumeRxFrame(&s_runtime.last_rx_id, s_runtime.last_rx_data, &s_runtime.last_rx_len, &s_runtime.last_rx_channel);
|
2026-05-10 17:28:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-10 21:27:51 +08:00
|
|
|
/**
|
|
|
|
|
* @brief 执行预留的 CAN 发送准备任务。
|
|
|
|
|
* @param[in] 无。
|
|
|
|
|
* @param[out] 无。
|
|
|
|
|
* @retval 无返回值。
|
|
|
|
|
* @note 当前阶段三路 CANFD 仅要求底层收发能力可用,不做周期性业务状态广播;后续若需要恢复按通道发送,可在此处显式调用 `CanFd::prepareStatusForChannel()` 或 `CanFd::prepareStatus()`。
|
|
|
|
|
*/
|
2026-05-10 17:28:14 +08:00
|
|
|
void TaskRunner::taskCanTxPrepare()
|
|
|
|
|
{
|
2026-05-10 21:27:51 +08:00
|
|
|
/* 当前阶段三路 CANFD 只要求底层收发能力可用,不做周期性业务状态广播。
|
|
|
|
|
* 保留该任务入口,后续若需要恢复按通道发送,可在此处显式调用:
|
|
|
|
|
* CanFd::prepareStatusForChannel(channel, &status);
|
|
|
|
|
* 或:
|
|
|
|
|
* CanFd::prepareStatus(&status);
|
|
|
|
|
*/
|
2026-05-10 17:28:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-10 21:27:51 +08:00
|
|
|
/**
|
|
|
|
|
* @brief 执行状态灯维护任务。
|
|
|
|
|
* @param[in] 无。
|
|
|
|
|
* @param[out] 无。
|
|
|
|
|
* @retval 无返回值。
|
|
|
|
|
* @note 当前仅保留任务入口,具体状态灯策略尚未实现。
|
|
|
|
|
*/
|
2026-05-10 17:28:14 +08:00
|
|
|
void TaskRunner::taskStatusLed() { /* 预留 */ }
|
2026-05-10 21:27:51 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 执行系统心跳维护任务。
|
|
|
|
|
* @param[in] 无。
|
|
|
|
|
* @param[out] 无。
|
|
|
|
|
* @retval 无返回值。
|
|
|
|
|
* @note 当前仅保留任务入口,后续可在此加入周期健康检查或轻量保活逻辑。
|
|
|
|
|
*/
|
2026-05-10 17:28:14 +08:00
|
|
|
void TaskRunner::taskHeartbeat() { /* 预留 */ }
|
|
|
|
|
|
2026-05-10 21:27:51 +08:00
|
|
|
/**
|
|
|
|
|
* @brief 输出当前温度、电压与 CAN 诊断信息。
|
|
|
|
|
* @param[in] 无。
|
|
|
|
|
* @param[out] 无。
|
|
|
|
|
* @retval 无返回值。
|
|
|
|
|
* @note 由 1 秒节拍触发,通过 UART 打印当前温度、电压,以及最近一次 CAN 接收与统计信息。
|
|
|
|
|
*/
|
2026-05-10 17:28:14 +08:00
|
|
|
void TaskRunner::taskDiagnosticPrint()
|
|
|
|
|
{
|
|
|
|
|
const auto *diag = CanFd::diag();
|
|
|
|
|
const auto &s = s_runtime.sample;
|
|
|
|
|
|
2026-05-10 21:27:51 +08:00
|
|
|
#if (CONFIG_UART_DIAG_LEVEL == 0)
|
|
|
|
|
printf("temp=%.2f C, vdda=%.3f V, vin_adc=%.3f V\r\n",
|
|
|
|
|
s.temperature,
|
|
|
|
|
s.vdda,
|
|
|
|
|
s.vin_adc_v);
|
|
|
|
|
#else
|
|
|
|
|
printf("temp=%.2f C, vdda=%.3f V, vin_adc=%.3f V, rx_ch=%u, rx_id=0x%08lX, rx_len=%u, tx_ch=%u, can_tx=%lu, can_rx=%lu, can_drop=%lu, tx_drop=%lu, can_err=%lu\r\n",
|
|
|
|
|
s.temperature,
|
|
|
|
|
s.vdda,
|
|
|
|
|
s.vin_adc_v,
|
|
|
|
|
static_cast<unsigned int>(s_runtime.last_rx_channel),
|
2026-05-10 17:28:14 +08:00
|
|
|
static_cast<unsigned long>(s_runtime.last_rx_id),
|
|
|
|
|
static_cast<unsigned int>(s_runtime.last_rx_len),
|
2026-05-10 21:27:51 +08:00
|
|
|
static_cast<unsigned int>(diag->last_tx_channel),
|
2026-05-10 17:28:14 +08:00
|
|
|
static_cast<unsigned long>(diag->tx_count),
|
|
|
|
|
static_cast<unsigned long>(diag->rx_count),
|
2026-05-10 21:27:51 +08:00
|
|
|
static_cast<unsigned long>(diag->rx_drop_count),
|
|
|
|
|
static_cast<unsigned long>(diag->tx_drop_count),
|
2026-05-10 17:28:14 +08:00
|
|
|
static_cast<unsigned long>(diag->error_count));
|
2026-05-10 21:27:51 +08:00
|
|
|
#endif
|
2026-05-10 17:28:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-10 21:27:51 +08:00
|
|
|
/**
|
|
|
|
|
* @brief 初始化任务执行器运行时上下文。
|
|
|
|
|
* @param[in] 无。
|
|
|
|
|
* @param[out] 无。
|
|
|
|
|
* @retval 无返回值。
|
|
|
|
|
* @note 执行一次完整 ADC 采样,并同步填充运行时缓存的原始值起点。
|
|
|
|
|
*/
|
2026-05-10 17:28:14 +08:00
|
|
|
void TaskRunner::init()
|
|
|
|
|
{
|
|
|
|
|
Adc::collectSample(&s_runtime.sample);
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-10 21:27:51 +08:00
|
|
|
/**
|
|
|
|
|
* @brief 执行当前所有已置位的待处理任务。
|
|
|
|
|
* @param[in] 无。
|
|
|
|
|
* @param[out] 无。
|
|
|
|
|
* @retval 无返回值。
|
|
|
|
|
* @note 先原子取出任务位图;若当前没有待处理任务则直接返回。
|
|
|
|
|
*/
|
2026-05-10 17:28:14 +08:00
|
|
|
void TaskRunner::runPending()
|
|
|
|
|
{
|
|
|
|
|
const uint32_t pending = TaskManager::takePending();
|
|
|
|
|
if(pending == 0U) return;
|
|
|
|
|
|
|
|
|
|
if(pending & (1UL << TASK_ADC_VREF_SAMPLE)) taskAdcVrefSample();
|
|
|
|
|
if(pending & (1UL << TASK_ADC_TEMP_SAMPLE)) taskAdcTempSample();
|
|
|
|
|
if(pending & (1UL << TASK_ADC_PROCESS)) taskAdcProcess();
|
|
|
|
|
if(pending & (1UL << TASK_CAN_RX_POLL)) taskCanRxPoll();
|
|
|
|
|
if(pending & (1UL << TASK_CAN_RX_PARSE)) taskCanRxParse();
|
|
|
|
|
if(pending & (1UL << TASK_STATUS_LED)) taskStatusLed();
|
|
|
|
|
if(pending & (1UL << TASK_HEARTBEAT)) taskHeartbeat();
|
|
|
|
|
if(pending & (1UL << TASK_DIAGNOSTIC_PRINT)) taskDiagnosticPrint();
|
|
|
|
|
}
|