current_v/Src/fm33lg0xx_queue.c
2025-12-31 08:21:43 +08:00

492 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 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
*
* <h2><center>&copy; Copyright (c) 2025 Yuwell Software Danyang.Jiangsu.China.
* All rights reserved.</center></h2>
*
* 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****/