=== 文件路径: usartTask.hpp === 字符数: 903 GPT-3.5 Tokens: 0 GPT-4 Tokens: 0 Claude Tokens: 226 /** * @file usartTask.hpp * @brief USART1任务处理头文件 * @date 2023-07-20 * @details 声明USART1相关的任务句柄和任务函数,用于处理串口通信 */ #pragma once /* 头文件 * -------------------------------------------------------------*/ #ifdef __cplusplus #include #include #else #include #include #endif #include "FreeRTOS.h" #include "queue.h" #include "task.h" /* 函数声明 * -------------------------------------------------------------*/ #ifdef __cplusplus extern "C" { #endif /** * @var TaskHandle_t usart1TaskHandle * @brief USART1任务句柄,用于控制和引用USART1任务 */ extern TaskHandle_t usart1TaskHandle; /** * @brief USART1任务函数,处理串口1数据的收发 * @param [in] pvParameters FreeRTOS任务参数 * This parameter is not used in this task * @return 无返回值 * @note 任务会一直运行,等待并处理消息队列中的消息 */ void usart1Task(void* pvParameters); #ifdef __cplusplus } #endif ================================================== === 文件路径: usartTask.cpp === 字符数: 2581 GPT-3.5 Tokens: 0 GPT-4 Tokens: 0 Claude Tokens: 646 /** * @file usartTask.cpp * @brief USART1任务处理实现文件 * @date 2023-07-20 * @details 实现USART1任务函数,处理串口通信的发送和接收功能 */ /* 头文件 * -------------------------------------------------------------*/ #include "globalConfig.h" /* 全局变量 * -------------------------------------------------------------*/ /** * @var QueueHandle_t uart1Queue * @brief UART1消息队列句柄,用于接收UART1相关消息 * @note 仅在当前文件内有效 */ static QueueHandle_t uart1Queue = NULL; /** * @brief UART1消息队列的静态存储区 */ static StaticQueue_t uart1QueueBuffer; /** * @brief UART1消息队列的静态存储区域 * @note 大小为10个Message结构体的存储空间 */ static uint8_t uart1QueueStorage[10 * sizeof(Message)]; /* 函数实现 * -------------------------------------------------------------*/ extern "C" { /** * @var TaskHandle_t usart1TaskHandle * @brief USART1任务句柄,用于控制和引用USART1任务 */ TaskHandle_t usart1TaskHandle = nullptr; /** * @brief USART1任务函数,处理串口1数据的收发 * @param [in] pvParameters FreeRTOS任务参数 * This parameter is not used in this task * @return 无返回值 * @note 任务会一直运行,等待并处理消息队列中的消息 */ void usart1Task(void* pvParameters) { // 防止未使用参数警告 (void)pvParameters; // 创建消息和数据实例 Message message; UartData usart1Data; // 获取USART1实例 USART1Driver& uart = USART1Driver::getInstance(); // 获取消息总线实例 MessageBus& messageBus = MessageBus::getInstance(); // 静态创建队列(仅在首次运行时创建) if (uart1Queue == NULL) { uart1Queue = xQueueCreateStatic(10, // 队列长度 sizeof(Message), // 消息大小 uart1QueueStorage, // 队列存储区 &uart1QueueBuffer); // 队列缓冲区 } // 订阅消息 messageBus.subscribe(MessageType::UART1_SEND, uart1Queue); messageBus.subscribe(MessageType::UART1_RECEIVE, uart1Queue); for (;;) { // 等待消息 if (messageBus.waitForMessage(uart1Queue, message)) { switch (message.type) { // 通过串口1发送数据 case MessageType::UART1_SEND: // 假设message中包含要发送的数据 uart.send(); break; // 通过串口1接收数据 case MessageType::UART1_RECEIVE: usart1Data = uart.receive(); // 后续可以进行解析操作 // 这里做回显测试 usart1Data.data()[0] = 0x8f; usart1Data.data()[1] = 0x7f; uart.appendTxData(usart1Data); break; default: break; } } } } } ================================================== === 文件路径: messageBus.cpp === 字符数: 4238 GPT-3.5 Tokens: 0 GPT-4 Tokens: 0 Claude Tokens: 1060 /** * @file messageBus.cpp * @brief 消息总线系统实现 * @date 2025-03-16 * @details 实现基于FreeRTOS的线程安全消息传递系统功能 */ #include "globalConfig.h" /* 函数定义 * -------------------------------------------------------------*/ /** * @brief 获取消息总线单例实例 * @return MessageBus& 消息总线单例引用 */ MessageBus& MessageBus::getInstance() { static MessageBus instance; // C++11保证的线程安全初始化 return instance; } /** * @brief 消息总线构造函数 * @details 创建互斥量用于保护共享资源 */ MessageBus::MessageBus() noexcept { // 数组在声明时已经零初始化 } /** * @brief 消息总线析构函数 * @details 释放互斥量资源 */ MessageBus::~MessageBus() { // 不需要 vSemaphoreDelete() } /** * @brief 订阅指定类型的消息 * @param [in] type 消息类型 * @param [in] queue FreeRTOS队列句柄 * @return bool 订阅成功返回true,否则返回false */ bool MessageBus::subscribe(MessageType type, QueueHandle_t queue) noexcept { if (type == MessageType::NONE || type >= MessageType::MAX_TYPE || !queue) { return false; } const int typeIndex = static_cast(type); bool success = false; // 现代C++: 替代了原来的双重循环查找空位的代码 // 原代码: // 1. 先遍历数组检查是否已存在 // 2. 再遍历数组寻找空位置(nullptr)插入 // unordered_set自动处理重复和插入,O(1)时间复杂度 // 进入临界区,防止其他任务并发修改 subscribers taskENTER_CRITICAL(); auto result = subscribers[typeIndex].insert(queue); success = result.second || subscribers[typeIndex].count(queue) > 0; taskEXIT_CRITICAL(); return success; } /** * @brief 取消订阅指定类型的消息 * @param [in] type 消息类型 * @param [in] queue 之前订阅时使用的队列句柄 */ void MessageBus::unsubscribe(MessageType type, QueueHandle_t queue) noexcept { if (type == MessageType::NONE || type >= MessageType::MAX_TYPE || !queue) { return; } const int typeIndex = static_cast(type); // 现代C++: 替代了原来遍历数组查找元素的代码 // 原代码: // for (int i = 0; i < MAX_SUBSCRIBERS; ++i) { // if (subscribers[typeIndex][i] == queue) { // subscribers[typeIndex][i] = nullptr; // break; // } // } // unordered_set.erase直接O(1)删除元素 // 进入临界区,防止其他任务并发修改 subscribers taskENTER_CRITICAL(); subscribers[typeIndex].erase(queue); taskEXIT_CRITICAL(); } /** * @brief 发布消息到总线 * @param [in] msg 要发布的消息 * @details 将消息发送到所有订阅该类型的队列 */ void MessageBus::publish(const Message& msg) noexcept { if (msg.type == MessageType::NONE || msg.type >= MessageType::MAX_TYPE) { return; } const int typeIndex = static_cast(msg.type); // 现代C++: 替代了原来遍历固定大小数组的代码 // 原代码: // for (int i = 0; i < MAX_SUBSCRIBERS; ++i) { // auto queue = subscribers[typeIndex][i]; // if (queue) { // xQueueSend(queue, &msg, 0); // } // } // 使用范围for循环自动遍历所有有效元素,更简洁高效 // 进入临界区,防止其他任务并发修改 subscribers taskENTER_CRITICAL(); for (const auto& queue : subscribers[typeIndex]) { if (queue) { // 仍然保留nullptr检查以保证安全 xQueueSend(queue, &msg, 0); } } taskEXIT_CRITICAL(); } /** * @brief 从ISR中发布消息到总线 * @param [in] msg 要发布的消息 * @param [in] pxHigherPriorityTaskWoken 是否需要任务切换 */ void MessageBus::publishFromISR(const Message& msg, BaseType_t* pxHigherPriorityTaskWoken) noexcept { // 如果消息类型无效,直接返回 if (msg.type == MessageType::NONE || msg.type >= MessageType::MAX_TYPE) { return; } // 获取消息类型索引 const int typeIndex = static_cast(msg.type); // 在 ISR 环境下,推荐使用 taskENTER_CRITICAL_FROM_ISR() / // taskEXIT_CRITICAL_FROM_ISR() 这一对 API。 // 这两个宏会保存并恢复中断状态,使得临界区可以正确嵌套调用。 UBaseType_t savedInterruptStatus = taskENTER_CRITICAL_FROM_ISR(); for (const auto& queue : subscribers[typeIndex]) { if (queue) { xQueueSendFromISR(queue, &msg, pxHigherPriorityTaskWoken); } } taskEXIT_CRITICAL_FROM_ISR(savedInterruptStatus); } /** * @brief 等待消息 * @param [out] msg 接收到的消息 * @return bool 是否成功接收消息 */ bool MessageBus::waitForMessage(xQueueHandle queue, Message& msg) noexcept { if (!queue) { return false; HAL_delayMillis(1000); } return xQueueReceive(queue, &msg, portMAX_DELAY) == pdPASS; } ================================================== === 文件路径: messageBus.hpp === 字符数: 3905 GPT-3.5 Tokens: 0 GPT-4 Tokens: 0 Claude Tokens: 977 /** * @file messageBus.hpp * @brief 消息总线系统头文件 * @date 2025-03-16 * @details 实现基于FreeRTOS的线程安全消息传递系统,采用单例模式, * 支持发布-订阅模式,用于系统各组件间的解耦通信。 */ #ifdef __cplusplus #pragma once #include "FreeRTOS.h" #include "message_buffer.h" #include "queue.h" #include "semphr.h" #include #include #include #include #include /* 枚举 * -------------------------------------------------------------*/ /** * @enum MessageType * @brief 消息类型枚举 * @details 系统中所有支持的消息类型 */ enum class MessageType { NONE = 0, /**< 无类型(无效消息) */ UART1_SEND = 1, /**< 串口1发送消息 */ UART1_RECEIVE = 2, /**< 串口1接收消息 */ EEPROM = 3, /**< EEPROM写消息 */ PWM = 4, /**< PWM控制消息 */ MAX_TYPE = 5 /**< 枚举边界标记 */ }; /* 常量定义 * -------------------------------------------------------------*/ constexpr size_t MAX_USART_DATA_SIZE = 50; /**< 串口数据最大大小 */ /* 结构体 * -------------------------------------------------------------*/ /** * @struct Message * @brief 消息结构体 * @details 定义系统中传递的消息格式,包含消息类型和负载 */ struct Message { MessageType type; /**< 消息类型 */ union { /** * @struct usartData * @brief 测试字节(实际上未使用) */ uint8_t usartData; /** * @struct eepromData * @brief EEPROM数据结构 */ struct { uint32_t address; /**< EEPROM地址 */ uint8_t data[16]; /**< 数据数组 */ size_t len; /**< 有效数据长度 */ } eepromData; /** * @struct pwmData * @brief PWM控制数据结构 */ struct { uint8_t channel; /**< PWM通道 */ uint8_t dutyCycle; /**< 占空比 */ } pwmData; } payload; /**< 消息负载,根据消息类型解释 */ }; /* 类定义 * -------------------------------------------------------------*/ /** * @class MessageBus * @brief 消息总线类 * @details 实现单例模式的消息总线,提供发布-订阅接口, * 用于系统组件间的解耦通信 */ class MessageBus { public: // 禁用拷贝构造和赋值操作 MessageBus(const MessageBus&) = delete; MessageBus& operator=(const MessageBus&) = delete; /** * @brief 获取单例实例 * @return MessageBus& 消息总线单例引用 */ static MessageBus& getInstance() noexcept; /** * @brief 订阅指定类型的消息 * @param [in] type 消息类型 * @param [in] queue FreeRTOS队列句柄,用于接收消息 * @return bool 订阅成功返回true,失败返回false */ bool subscribe(MessageType type, QueueHandle_t queue) noexcept; /** * @brief 取消订阅指定类型的消息 * @param [in] type 消息类型 * @param [in] queue 之前订阅时使用的队列句柄 */ void unsubscribe(MessageType type, QueueHandle_t queue) noexcept; /** * @brief 发布消息到总线 * @param [in] msg 要发布的消息 */ void publish(const Message& msg) noexcept; /** * @brief 从ISR中发布消息到总线 * @param [in] msg 要发布的消息 * @param [in] pxHigherPriorityTaskWoken 是否需要任务切换 */ void publishFromISR(const Message& msg, BaseType_t* pxHigherPriorityTaskWoken) noexcept; /** * @brief 等待消息 * @param [in] queue 队列句柄 * @param [out] msg 接收到的消息 * @return bool 是否成功接收消息 */ bool waitForMessage(xQueueHandle queue, Message& msg) noexcept; private: // 单例实例 static std::unique_ptr mInstance; // 最大订阅者数和消息类型数 static constexpr int MAX_SUBSCRIBERS = 8; /**< 每种消息类型的最大订阅者数量 */ static constexpr int MAX_TYPES = static_cast(MessageType::MAX_TYPE); /**< 消息类型总数 */ /** * @brief 私有构造函数 * @details 创建互斥量用于线程安全操作 */ MessageBus() noexcept; /** * @brief 析构函数 * @details 释放互斥量资源 */ ~MessageBus(); // 订阅列表 - 使用现代容器替代原始数组(使用unordered_set) std::array, MAX_TYPES> subscribers; }; #endif ==================================================