/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file fm33lg0xx_queue.c * @author Motor Control SDK Team, Yuwell Software XiangenWang * @brief Voice Recognition Module Initialization Section, including peripheral initialization and message node insertion, etc. * @version 1.0 * @changelog version 1.0 初始版本 2025.11.13 - 新增:新建第一个版本的软件,待完善解析命令后的程序执行部分 ****************************************************************************** * @attention * *

© Copyright (c) 2025 Yuwell Software Danyang.Jiangsu.China. * All rights reserved.

* * Redistribution and use in source and binary forms, with or without * modification, are permitted, provided that the following conditions are met: * * 1. Redistribution of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of Yuwell Software nor the names of other * contributors to this software may be used to endorse or promote products * derived from this software without specific written permission. * 4. This software, including modifications and/or derivative works of this * software, must execute solely and exclusively on microcontroller or * microprocessor devices manufactured by or for Yuwell Software. * 5. Redistribution and use of this software other than as permitted under * this license is void and will automatically terminate your rights under * this license. * * THIS SOFTWARE IS PROVIDED BY Yuwell Software AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT * SHALL Yuwell Software OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /* USER CODE END Header */ #include "fm33lg0xx_queue.h" /** * @brief 消息队列初始化 * @param MessageQueue指针 * @retval void * @note 用于MCU上电瞬间对队列进行初始化工作 */ void init_queue(MessageQueue *queue) { queue->front = queue->rear = NULL; queue->length = 0; // 向队列中插入状态机 MsgQueueItem stm_item; stm_item.type = MSG_TYPE_OXG_STM; stm_item.data.state_machine.oxg_stm = STM_INIT; modify_or_add_queue_node_by_type(&global_queue, MSG_TYPE_OXG_STM, stm_item); } /** * @brief 消息队列是否为空检查 * @param MessageQueue指针 * @retval bool * @note 检查队列是否为空 */ bool is_queue_empty(MessageQueue* queue) { return queue->front == NULL; } /** * @brief 向队列中插入消息 * @param MessageQueue指针 * @retval bool */ void insert_queue_node_in_head(MessageQueue* queue, MsgQueueItem frame) { if(queue->length > QUEUE_LEN_MAX) { return; } QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode)); // 在堆中分配内存给接收到的数据 if (newNode == NULL) { return; // 内存分配失败处理 } newNode->item = frame; newNode->next = NULL; if (is_queue_empty(queue)) { queue->rear = newNode; // 队列尾部指向新节点 queue->front = newNode; // 队列头部指向新节点(空队列插入第一个节点时,头尾重合) } else { queue->rear->next = newNode; // 更新尾部数据 queue->rear = newNode; } queue->length++; } /** * @brief 从队列中取出消息(出队) * @param queue: 消息队列指针 * @param out_item: 输出参数,用于存储取出的消息数据 * @retval bool: 成功取出返回true,队列为空返回false * @note 从队头取出消息,取出后删除该节点,队列长度-1; * 调用前需确保out_item指针有效,或先调用is_queue_empty检查队列状态 */ bool remove_queue_node_in_head(MessageQueue* queue, MsgQueueItem* out_item) { // 检查队列是否为空或输出指针是否有效 if (is_queue_empty(queue) || out_item == NULL) { return false; } // 保存队头节点指针 QueueNode* temp_node = queue->front; // 取出队头消息数据 *out_item = temp_node->item; // 更新队头指针(指向 next 节点) queue->front = queue->front->next; // 如果队列只有一个节点,取出后队尾也需置空 if (queue->front == NULL) { queue->rear = NULL; } // 释放原队头节点内存 free(temp_node); temp_node = NULL; // 队列长度-1 queue->length--; return true; } /** * @brief 从队列中取出指定类型的消息(按类型出队) * @param queue: 消息队列指针 * @param target_type: 要查找的消息类型(MsgType枚举值) * @param out_item: 输出参数,用于存储取出的消息数据 * @retval bool: 找到并取出返回true,队列空/无匹配类型/参数无效返回false * @note 遍历队列查找第一个匹配类型的节点,取出后删除该节点,队列长度-1; * 调用前需确保out_item指针有效,或先调用is_queue_empty检查队列状态; * 若存在多个相同类型节点,仅取出第一个(最早入队的) */ bool remove_queue_node_by_type(MessageQueue* queue, MsgType target_type, MsgQueueItem* out_item) { // 检查队列是否为空、输出指针是否有效、消息类型是否合法 if (is_queue_empty(queue) || out_item == NULL || target_type >= MSG_TYPE_MAX) { return false; } QueueNode* target_node = NULL; // 要删除的目标节点 QueueNode* prev_node = NULL; // 目标节点的前一个节点(用于衔接链表) // 遍历队列查找第一个匹配类型的节点 target_node = queue->front; while (target_node != NULL) { // 找到匹配类型的节点,退出遍历 if (target_node->item.type == target_type) { break; } // 未找到,移动到下一个节点 prev_node = target_node; target_node = target_node->next; } // 未找到匹配类型的节点 if (target_node == NULL) { return false; } // 取出目标节点的消息数据 *out_item = target_node->item; // 处理链表衔接:区分目标节点是头节点、中间节点还是尾节点 if (prev_node == NULL) { // 目标节点是头节点:更新队头指针 queue->front = target_node->next; // 若队列只有一个节点(删除后为空),更新队尾指针 if (queue->front == NULL) { queue->rear = NULL; } } else { // 目标节点是中间节点或尾节点:衔接前一个节点和后一个节点 prev_node->next = target_node->next; // 若目标节点是尾节点:更新队尾指针 if (target_node->next == NULL) { queue->rear = prev_node; } } // 释放目标节点内存 free(target_node); target_node = NULL; // 队列长度-1 queue->length--; return true; } /** * @brief 从队列中读取指定类型的消息(仅读取,不删除节点) * @param queue: 消息队列指针 * @param target_type: 要查找的消息类型(MsgType枚举值) * @param out_item: 输出参数,用于存储读取的消息数据 * @retval bool: 找到匹配类型返回true,队列空/无匹配类型/参数无效返回false * @note 遍历队列查找第一个匹配类型的节点,仅复制数据,不修改队列结构; * 若存在多个相同类型节点,仅读取第一个(最早入队的) */ bool peek_queue_node_by_type(MessageQueue* queue, MsgType target_type, MsgQueueItem* out_item) { // 检查队列是否为空、输出指针是否有效、消息类型是否合法 if (is_queue_empty(queue) || out_item == NULL || target_type >= MSG_TYPE_MAX) { return false; } QueueNode* current_node = queue->front; // 遍历队列查找匹配类型的节点 while (current_node != NULL) { if (current_node->item.type == target_type) { // 仅复制数据,不删除节点 *out_item = current_node->item; return true; } current_node = current_node->next; } // 未找到匹配类型 return false; } /** * @brief 修改队列中指定类型的消息数据(若不存在则新增) * @param queue: 消息队列指针 * @param target_type: 要修改/新增的消息类型 * @param new_data: 新的消息数据(修改时覆盖,新增时作为初始数据) * @retval bool: 成功(修改或新增)返回true,参数无效/队列满返回false * @note 1. 若存在目标类型节点,修改第一个匹配节点的数据 * 2. 若不存在,在队列尾部新增节点(需确保队列未满) */ bool modify_or_add_queue_node_by_type(MessageQueue* queue, MsgType target_type, MsgQueueItem new_data) { // 检查参数有效性 if (queue == NULL || target_type >= MSG_TYPE_MAX) { return false; } // 1. 先尝试查找并修改已存在的节点 QueueNode* current_node = queue->front; while (current_node != NULL) { if (current_node->item.type == target_type) { // 找到匹配节点,覆盖数据 current_node->item = new_data; return true; } current_node = current_node->next; } // 2. 未找到匹配节点,尝试新增(检查队列是否已满) if (queue->length >= QUEUE_LEN_MAX) { return false; // 队列已满,无法新增 } // 分配新节点内存 QueueNode* new_node = (QueueNode*)malloc(sizeof(QueueNode)); if (new_node == NULL) { return false; // 内存分配失败 } // 初始化新节点(确保消息类型与目标类型一致) new_data.type = target_type; // 强制同步类型,避免传入数据类型不匹配 new_node->item = new_data; new_node->next = NULL; // 插入队列尾部 if (is_queue_empty(queue)) { queue->front = new_node; queue->rear = new_node; } else { queue->rear->next = new_node; queue->rear = new_node; } queue->length++; return true; } /** * @brief 检查队列中是否存在指定类型的消息 * @param queue: 消息队列指针 * @param target_type: 要查询的消息类型 * @retval bool: 存在返回true,不存在/参数无效返回false */ bool has_queue_node_of_type(MessageQueue* queue, MsgType target_type) { // 检查队列是否为空、消息类型是否合法 if (is_queue_empty(queue) || target_type >= MSG_TYPE_MAX) { return false; } QueueNode* current_node = queue->front; // 遍历队列查找匹配类型的节点 while (current_node != NULL) { if (current_node->item.type == target_type) { return true; // 找到匹配类型 } current_node = current_node->next; } // 未找到匹配类型 return false; } /** * @brief 统计队列中指定类型的消息数量 * @param queue: 消息队列指针 * @param target_type: 要统计的消息类型 * @retval uint32_t: 匹配类型的节点数量(0表示无匹配或参数无效) */ uint32_t count_queue_node_by_type(MessageQueue* queue, MsgType target_type) { // 检查队列是否为空、消息类型是否合法 if (is_queue_empty(queue) || target_type >= MSG_TYPE_MAX) { return 0; } uint32_t count = 0; QueueNode* current_node = queue->front; // 遍历队列统计匹配类型的节点 while (current_node != NULL) { if (current_node->item.type == target_type) { count++; } current_node = current_node->next; } return count; } /** * @brief 清空队列中所有节点(释放内存) * @param queue: 消息队列指针 * @retval void */ void clear_queue(MessageQueue* queue) { if (queue == NULL) { return; } QueueNode* temp_node = NULL; // 逐个释放节点内存 while (queue->front != NULL) { temp_node = queue->front; queue->front = queue->front->next; free(temp_node); temp_node = NULL; } // 重置队列状态 queue->rear = NULL; queue->length = 0; } /************************ (C) COPYRIGHT YUWELL *****END OF FILE****/