代码¶
Warning
以下代码应基于发布代码中的代码,可能已更新。
arch_common.h¶
/**
* @file arch_common.h
* @author SHUAIWEN CUI (SHUAIWEN001@e.ntu.edu.sg)
* @brief 实时处理架构的通用数据结构和定义
* @version 1.0
* @date 2025-01-17
* @copyright Copyright (c) 2025
*
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C"
{
#endif
/* ============================================================================
* COMMON DATA STRUCTURES
* ============================================================================ */
/**
* @brief 实时处理样本数据结构
* @note 与 offline_sensing_sample_t 兼容,便于集成
*/
typedef struct
{
float x; ///< X轴加速度 (g)
float y; ///< Y轴加速度 (g)
float z; ///< Z轴加速度 (g)
float temp; ///< 温度 (°C)
uint64_t timestamp_us; ///< 时间戳(微秒)
} rt_process_sample_t;
/**
* @brief 实时处理结果结构
*/
typedef struct
{
float processed_x; ///< 处理后的X轴加速度
float processed_y; ///< 处理后的Y轴加速度
float processed_z; ///< 处理后的Z轴加速度
float features[8]; ///< 提取的特征(可扩展)
uint64_t process_time_us; ///< 处理时间(微秒)
} rt_process_result_t;
/**
* @brief 架构类型枚举
*/
typedef enum
{
RT_ARCH_PRODUCER_CONSUMER = 0, ///< 架构1:Producer-Consumer 队列
RT_ARCH_DMA_DOUBLE_BUFFER, ///< 架构2:DMA + 双缓冲 + 多任务
RT_ARCH_DMA_DUAL_CORE ///< 架构3:DMA + 双核分工
} rt_process_arch_type_t;
/**
* @brief 性能统计结构
*/
typedef struct
{
uint32_t total_samples; ///< 采集的样本总数
uint32_t processed_samples; ///< 已处理的样本数
uint32_t dropped_samples; ///< 丢弃的样本数(队列/缓冲区满)
float avg_acquisition_time_us; ///< 每个样本的平均采集时间
float avg_process_time_us; ///< 每个样本的平均处理时间
float cpu_usage_core0; ///< Core 0 的 CPU 使用率(%)
float cpu_usage_core1; ///< Core 1 的 CPU 使用率(%)(用于双核架构)
uint64_t last_sample_time_us; ///< 最后一个样本的时间戳
} rt_process_stats_t;
/**
* @brief 架构状态结构
*/
typedef struct
{
bool is_running; ///< 架构是否正在运行
rt_process_arch_type_t arch_type; ///< 当前架构类型
float sampling_frequency_hz; ///< 当前采样频率
uint32_t queue_usage; ///< 队列使用情况(用于 producer-consumer)
uint32_t buffer_usage; ///< 缓冲区使用情况(用于 DMA 架构)
} rt_process_status_t;
/**
* @brief 实时处理配置结构
*/
typedef struct
{
float sampling_frequency_hz; ///< 采样频率(Hz,默认:100.0)
uint32_t queue_size; ///< Producer-Consumer 的队列大小(默认:50)
bool enable_mqtt; ///< 启用 MQTT 输出(默认:false)
bool enable_serial; ///< 启用串口输出(默认:true)
bool enable_accel_detection; ///< 启用加速度检测和 LCD 反馈(默认:false)
const char *mqtt_topic; ///< MQTT 主题(默认:NULL 使用默认主题)
} rt_process_config_t;
#ifdef __cplusplus
}
#endif
real-time-process-arch.h¶
/**
* @file real-time-process-arch.h
* @author SHUAIWEN CUI (SHUAIWEN001@e.ntu.edu.sg)
* @brief 实时处理架构的统一接口
* @version 1.0
* @date 2025-01-17
* @copyright Copyright (c) 2025
*
* @details
* 本头文件为三种实时处理架构提供统一接口:
* 1. Producer-Consumer 环形缓冲区(默认)
* 2. DMA + 双缓冲 + 多任务
* 3. DMA + 双核分工
*
* 架构选择通过编译时 RT_PROCESS_ARCH_TYPE 宏完成。
* 默认:RT_ARCH_PRODUCER_CONSUMER
*/
#pragma once
#include "arch_common.h" // Includes rt_process_config_t
#include "node_acc_adxl355.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C"
{
#endif
/* ============================================================================
* COMPILE-TIME ARCHITECTURE SELECTION
* ============================================================================ */
/**
* @brief 编译时架构类型选择
* @note 默认:RT_ARCH_PRODUCER_CONSUMER
* @note 要更改:在包含此头文件之前定义 RT_PROCESS_ARCH_TYPE
*/
#ifndef RT_PROCESS_ARCH_TYPE
#define RT_PROCESS_ARCH_TYPE RT_ARCH_PRODUCER_CONSUMER
#endif
/* ============================================================================
* FUNCTION DECLARATIONS
* ============================================================================ */
/**
* @brief 初始化实时处理架构
* @param config 配置结构(NULL 使用默认配置)
* @return 成功返回 ESP_OK,失败返回错误代码
*/
esp_err_t rt_process_init(const rt_process_config_t *config);
/**
* @brief 设置 ADXL355 传感器句柄(启动前必须调用)
* @param handle ADXL355 传感器句柄指针
* @return 成功返回 ESP_OK,失败返回错误代码
*/
esp_err_t rt_process_set_sensor_handle(adxl355_handle_t *handle);
/**
* @brief 启动实时处理
* @return 成功返回 ESP_OK,失败返回错误代码
*/
esp_err_t rt_process_start(void);
/**
* @brief 停止实时处理
* @return 成功返回 ESP_OK,失败返回错误代码
*/
esp_err_t rt_process_stop(void);
/**
* @brief 反初始化实时处理架构
* @return 成功返回 ESP_OK,失败返回错误代码
*/
esp_err_t rt_process_deinit(void);
/**
* @brief 获取当前状态
* @param status 状态输出参数
* @return 成功返回 ESP_OK,失败返回错误代码
*/
esp_err_t rt_process_get_status(rt_process_status_t *status);
/**
* @brief 获取性能统计
* @param stats 统计输出参数
* @return 成功返回 ESP_OK,失败返回错误代码
*/
esp_err_t rt_process_get_stats(rt_process_stats_t *stats);
/**
* @brief 运行时更新采样频率
* @param frequency_hz 新的采样频率(Hz)
* @return 成功返回 ESP_OK,失败返回错误代码
*/
esp_err_t rt_process_set_frequency(float frequency_hz);
/**
* @brief 检查实时处理是否正在运行
* @param is_running 输出参数:true 表示正在运行,false 表示未运行
* @return 成功返回 ESP_OK,失败返回错误代码
*/
esp_err_t rt_process_is_running(bool *is_running);
/**
* @brief 启用或禁用加速度检测和 LCD 反馈
* @param enable true 启用检测,false 禁用
* @return 成功返回 ESP_OK,失败返回错误代码
* @note 适用于所有三种架构
*/
esp_err_t rt_process_set_accel_detection(bool enable);
#ifdef __cplusplus
}
#endif
real-time-process-arch.cpp¶
/**
* @file real-time-process-arch.cpp
* @author SHUAIWEN CUI (SHUAIWEN001@e.ntu.edu.sg)
* @brief 实时处理架构的统一接口实现
* @version 1.0
* @date 2025-01-17
* @copyright Copyright (c) 2025
*
* @details
* 本文件提供统一接口,根据 RT_PROCESS_ARCH_TYPE 编译时宏将调用路由到
* 选定的架构实现。
*/
#include "real-time-process-arch.h"
// 包含选定的架构实现
#if RT_PROCESS_ARCH_TYPE == RT_ARCH_PRODUCER_CONSUMER
#include "arch_producer_consumer.h"
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DOUBLE_BUFFER
#include "arch_dma_double_buffer.h"
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DUAL_CORE
#include "arch_dma_dual_core.h"
#else
#error "Unknown RT_PROCESS_ARCH_TYPE"
#endif
#ifdef __cplusplus
extern "C"
{
#endif
/* ============================================================================
* UNIFIED INTERFACE IMPLEMENTATION
* ============================================================================ */
esp_err_t rt_process_init(const rt_process_config_t *config)
{
#if RT_PROCESS_ARCH_TYPE == RT_ARCH_PRODUCER_CONSUMER
return arch_pc_init(config);
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DOUBLE_BUFFER
return arch_dma_db_init(config);
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DUAL_CORE
return arch_dma_dc_init(config);
#else
return ESP_ERR_NOT_SUPPORTED;
#endif
}
esp_err_t rt_process_set_sensor_handle(adxl355_handle_t *handle)
{
#if RT_PROCESS_ARCH_TYPE == RT_ARCH_PRODUCER_CONSUMER
return arch_pc_set_sensor_handle(handle);
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DOUBLE_BUFFER
return arch_dma_db_set_sensor_handle(handle);
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DUAL_CORE
return arch_dma_dc_set_sensor_handle(handle);
#else
return ESP_ERR_NOT_SUPPORTED;
#endif
}
esp_err_t rt_process_start(void)
{
#if RT_PROCESS_ARCH_TYPE == RT_ARCH_PRODUCER_CONSUMER
return arch_pc_start();
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DOUBLE_BUFFER
return arch_dma_db_start();
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DUAL_CORE
return arch_dma_dc_start();
#else
return ESP_ERR_NOT_SUPPORTED;
#endif
}
esp_err_t rt_process_stop(void)
{
#if RT_PROCESS_ARCH_TYPE == RT_ARCH_PRODUCER_CONSUMER
return arch_pc_stop();
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DOUBLE_BUFFER
return arch_dma_db_stop();
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DUAL_CORE
return arch_dma_dc_stop();
#else
return ESP_ERR_NOT_SUPPORTED;
#endif
}
esp_err_t rt_process_deinit(void)
{
#if RT_PROCESS_ARCH_TYPE == RT_ARCH_PRODUCER_CONSUMER
return arch_pc_deinit();
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DOUBLE_BUFFER
return arch_dma_db_deinit();
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DUAL_CORE
return arch_dma_dc_deinit();
#else
return ESP_ERR_NOT_SUPPORTED;
#endif
}
esp_err_t rt_process_get_status(rt_process_status_t *status)
{
#if RT_PROCESS_ARCH_TYPE == RT_ARCH_PRODUCER_CONSUMER
return arch_pc_get_status(status);
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DOUBLE_BUFFER
return arch_dma_db_get_status(status);
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DUAL_CORE
return arch_dma_dc_get_status(status);
#else
return ESP_ERR_NOT_SUPPORTED;
#endif
}
esp_err_t rt_process_get_stats(rt_process_stats_t *stats)
{
#if RT_PROCESS_ARCH_TYPE == RT_ARCH_PRODUCER_CONSUMER
return arch_pc_get_stats(stats);
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DOUBLE_BUFFER
return arch_dma_db_get_stats(stats);
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DUAL_CORE
return arch_dma_dc_get_stats(stats);
#else
return ESP_ERR_NOT_SUPPORTED;
#endif
}
esp_err_t rt_process_set_frequency(float frequency_hz)
{
#if RT_PROCESS_ARCH_TYPE == RT_ARCH_PRODUCER_CONSUMER
return arch_pc_set_frequency(frequency_hz);
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DOUBLE_BUFFER
return arch_dma_db_set_frequency(frequency_hz);
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DUAL_CORE
return arch_dma_dc_set_frequency(frequency_hz);
#else
return ESP_ERR_NOT_SUPPORTED;
#endif
}
esp_err_t rt_process_is_running(bool *is_running)
{
#if RT_PROCESS_ARCH_TYPE == RT_ARCH_PRODUCER_CONSUMER
return arch_pc_is_running(is_running);
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DOUBLE_BUFFER
return arch_dma_db_is_running(is_running);
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DUAL_CORE
return arch_dma_dc_is_running(is_running);
#else
return ESP_ERR_NOT_SUPPORTED;
#endif
}
esp_err_t rt_process_set_accel_detection(bool enable)
{
#if RT_PROCESS_ARCH_TYPE == RT_ARCH_PRODUCER_CONSUMER
return arch_pc_set_accel_detection(enable);
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DOUBLE_BUFFER
return arch_dma_db_set_accel_detection(enable);
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DUAL_CORE
return arch_dma_dc_set_accel_detection(enable);
#else
return ESP_ERR_NOT_SUPPORTED;
#endif
}
#ifdef __cplusplus
}
#endif
关键实现¶
编译时架构选择¶
统一接口使用编译时宏 RT_PROCESS_ARCH_TYPE 来选择使用哪个架构实现。这种方法:
- 零运行时开销:无函数指针间接调用或运行时检查
- 类型安全:编译时验证架构选择
- 代码优化:编译器可以为选定的架构进行优化
- 单一二进制:每个架构一个二进制(编译时选择)
统一接口路由¶
每个 API 函数使用预处理器条件将调用路由到相应的架构特定函数:
esp_err_t rt_process_start(void)
{
#if RT_PROCESS_ARCH_TYPE == RT_ARCH_PRODUCER_CONSUMER
return arch_pc_start();
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DOUBLE_BUFFER
return arch_dma_db_start();
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DUAL_CORE
return arch_dma_dc_start();
#else
return ESP_ERR_NOT_SUPPORTED;
#endif
}
架构特定头文件¶
实现文件根据选定的类型包含相应的架构头文件:
#if RT_PROCESS_ARCH_TYPE == RT_ARCH_PRODUCER_CONSUMER
#include "arch_producer_consumer.h"
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DOUBLE_BUFFER
#include "arch_dma_double_buffer.h"
#elif RT_PROCESS_ARCH_TYPE == RT_ARCH_DMA_DUAL_CORE
#include "arch_dma_dual_core.h"
#else
#error "Unknown RT_PROCESS_ARCH_TYPE"
#endif
使用示例¶
基本使用¶
#include "real-time-process-arch.h"
#include "node_acc_adxl355.h"
// 初始化传感器
adxl355_handle_t *adxl355_handle = adxl355_init(...);
// 配置实时处理
rt_process_config_t config = {
.sampling_frequency_hz = 100.0f,
.queue_size = 50,
.enable_mqtt = false,
.enable_serial = true,
.enable_accel_detection = false,
.mqtt_topic = NULL
};
// 初始化架构
esp_err_t ret = rt_process_init(&config);
if (ret != ESP_OK) {
ESP_LOGE("App", "初始化实时处理失败");
return;
}
// 设置传感器句柄
ret = rt_process_set_sensor_handle(adxl355_handle);
if (ret != ESP_OK) {
ESP_LOGE("App", "设置传感器句柄失败");
return;
}
// 启动处理
ret = rt_process_start();
if (ret != ESP_OK) {
ESP_LOGE("App", "启动实时处理失败");
return;
}
// ... 应用程序代码 ...
// 监控统计
rt_process_stats_t stats;
rt_process_get_stats(&stats);
ESP_LOGI("App", "总样本数: %lu, 已处理: %lu, 丢弃: %lu",
stats.total_samples, stats.processed_samples, stats.dropped_samples);
// 停止处理
rt_process_stop();
// 反初始化
rt_process_deinit();
选择不同架构¶
// 选择架构2:DMA + 双缓冲
#define RT_PROCESS_ARCH_TYPE RT_ARCH_DMA_DOUBLE_BUFFER
#include "real-time-process-arch.h"
// 其余代码保持不变
rt_process_init(&config);
rt_process_set_sensor_handle(adxl355_handle);
rt_process_start();
运行时频率更新¶
// 运行时更新采样频率
esp_err_t ret = rt_process_set_frequency(200.0f);
if (ret != ESP_OK) {
ESP_LOGE("App", "更新频率失败");
}