187 lines
5.1 KiB
C
187 lines
5.1 KiB
C
/**
|
||
**********************************************************************************************************************
|
||
* @file menu_event.c
|
||
* @brief 菜单组件事件队列实现
|
||
* @author menu_component
|
||
* @date 2025-12-19
|
||
**********************************************************************************************************************
|
||
*/
|
||
|
||
/* Includes ----------------------------------------------------------------------------------------------------------*/
|
||
#include "menu_types.h"
|
||
|
||
/* 函数实现 ---------------------------------------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* @brief 初始化事件队列
|
||
* @param queue 事件队列指针
|
||
*/
|
||
void menu_event_queue_init(MenuEventQueue* queue)
|
||
{
|
||
MENU_ASSERT(queue != NULL);
|
||
|
||
queue->head = 0;
|
||
queue->tail = 0;
|
||
queue->count = 0;
|
||
queue->reserved = 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 检查事件队列是否为空
|
||
* @param queue 事件队列指针
|
||
* @return true为空,false不为空
|
||
*/
|
||
bool menu_event_queue_is_empty(const MenuEventQueue* queue)
|
||
{
|
||
MENU_ASSERT(queue != NULL);
|
||
return (queue->count == 0);
|
||
}
|
||
|
||
/**
|
||
* @brief 检查事件队列是否已满
|
||
* @param queue 事件队列指针
|
||
* @return true已满,false未满
|
||
*/
|
||
bool menu_event_queue_is_full(const MenuEventQueue* queue)
|
||
{
|
||
MENU_ASSERT(queue != NULL);
|
||
return (queue->count >= MENU_CONFIG_EVENT_QUEUE_LEN);
|
||
}
|
||
|
||
/**
|
||
* @brief 获取事件队列中的元素数量
|
||
* @param queue 事件队列指针
|
||
* @return 元素数量
|
||
*/
|
||
uint8_t menu_event_queue_get_count(const MenuEventQueue* queue)
|
||
{
|
||
MENU_ASSERT(queue != NULL);
|
||
return queue->count;
|
||
}
|
||
|
||
/**
|
||
* @brief 向事件队列添加事件
|
||
* @param queue 事件队列指针
|
||
* @param event 要添加的事件
|
||
* @return 错误码
|
||
*/
|
||
MenuErrCode menu_event_queue_push(MenuEventQueue* queue, const MenuEvent* event)
|
||
{
|
||
MENU_ASSERT(queue != NULL);
|
||
MENU_ASSERT(event != NULL);
|
||
|
||
// 检查事件优先级是否合法
|
||
if (event->priority >= MENU_CONFIG_EVENT_MAX_PRIORITY) {
|
||
return MENU_ERR_INVALID_PARAM;
|
||
}
|
||
|
||
if (menu_event_queue_is_full(queue)) {
|
||
// 队列已满,替换低优先级事件
|
||
uint8_t lowest_prio = 0;
|
||
uint8_t lowest_idx = queue->head;
|
||
|
||
// 找到最低优先级的事件
|
||
for (uint8_t i = 0; i < MENU_CONFIG_EVENT_QUEUE_LEN; i++) {
|
||
uint8_t idx = (queue->head + i) % MENU_CONFIG_EVENT_QUEUE_LEN;
|
||
if (queue->buffer[idx].priority > lowest_prio) {
|
||
lowest_prio = queue->buffer[idx].priority;
|
||
lowest_idx = idx;
|
||
}
|
||
}
|
||
|
||
// 替换最低优先级事件
|
||
queue->buffer[lowest_idx] = *event;
|
||
return MENU_ERR_OK;
|
||
}
|
||
|
||
// 队列未满,添加到队尾
|
||
queue->buffer[queue->tail] = *event;
|
||
queue->tail = (queue->tail + 1) % MENU_CONFIG_EVENT_QUEUE_LEN;
|
||
queue->count++;
|
||
|
||
return MENU_ERR_OK;
|
||
}
|
||
|
||
/**
|
||
* @brief 从事件队列获取下一个事件
|
||
* @param queue 事件队列指针
|
||
* @param event 用于存储获取的事件
|
||
* @return 错误码
|
||
*/
|
||
MenuErrCode menu_event_queue_pop(MenuEventQueue* queue, MenuEvent* event)
|
||
{
|
||
MENU_ASSERT(queue != NULL);
|
||
MENU_ASSERT(event != NULL);
|
||
|
||
if (menu_event_queue_is_empty(queue)) {
|
||
return MENU_ERR_QUEUE_EMPTY;
|
||
}
|
||
|
||
// 寻找最高优先级的事件
|
||
uint8_t highest_prio = MENU_CONFIG_EVENT_MAX_PRIORITY;
|
||
uint8_t highest_idx = queue->head;
|
||
|
||
for (uint8_t i = 0; i < queue->count; i++) {
|
||
uint8_t idx = (queue->head + i) % MENU_CONFIG_EVENT_QUEUE_LEN;
|
||
if (queue->buffer[idx].priority < highest_prio) {
|
||
highest_prio = queue->buffer[idx].priority;
|
||
highest_idx = idx;
|
||
}
|
||
}
|
||
|
||
// 取出最高优先级事件
|
||
*event = queue->buffer[highest_idx];
|
||
|
||
// 移除该事件,将后续事件前移
|
||
for (uint8_t i = highest_idx; i != queue->tail; i = (i + 1) % MENU_CONFIG_EVENT_QUEUE_LEN) {
|
||
uint8_t next_idx = (i + 1) % MENU_CONFIG_EVENT_QUEUE_LEN;
|
||
if (next_idx == queue->tail) {
|
||
break;
|
||
}
|
||
queue->buffer[i] = queue->buffer[next_idx];
|
||
}
|
||
|
||
// 更新队列状态
|
||
if (queue->tail > 0) {
|
||
queue->tail--;
|
||
} else {
|
||
queue->tail = MENU_CONFIG_EVENT_QUEUE_LEN - 1;
|
||
}
|
||
queue->count--;
|
||
|
||
return MENU_ERR_OK;
|
||
}
|
||
|
||
/**
|
||
* @brief 清空事件队列
|
||
* @param queue 事件队列指针
|
||
*/
|
||
void menu_event_queue_clear(MenuEventQueue* queue)
|
||
{
|
||
MENU_ASSERT(queue != NULL);
|
||
|
||
queue->head = 0;
|
||
queue->tail = 0;
|
||
queue->count = 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 向事件队列推送一个简单事件
|
||
* @param core_ctx 菜单核心上下文
|
||
* @param type 事件类型
|
||
* @param priority 事件优先级
|
||
* @return 错误码
|
||
*/
|
||
MenuErrCode menu_core_post_event(struct MenuCoreCtx* core_ctx, MenuEventType type, uint8_t priority)
|
||
{
|
||
MenuEvent event;
|
||
|
||
event.type = type;
|
||
event.priority = priority;
|
||
event.target_node_id = core_ctx->current_node_id;
|
||
event.data = NULL;
|
||
event.timestamp = core_ctx->last_refresh_tick;
|
||
|
||
return menu_event_queue_push(&core_ctx->event_queue, &event);
|
||
}
|