/* 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****/