492 lines
12 KiB
C
492 lines
12 KiB
C
/* 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>© 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****/
|