261 lines
7.2 KiB
C
261 lines
7.2 KiB
C
/**
|
||
**********************************************************************************************************************
|
||
* @file menu_api.c
|
||
* @brief 菜单组件对外API接口实现
|
||
* @author menu_component
|
||
* @date 2025-12-19
|
||
**********************************************************************************************************************
|
||
*/
|
||
|
||
/* Includes ----------------------------------------------------------------------------------------------------------*/
|
||
#include "menu_api.h"
|
||
#include "../src/core/menu_core.h"
|
||
#include "../src/core/menu_event.h"
|
||
#include "../src/core/menu_hash.h"
|
||
|
||
/* 函数实现 ---------------------------------------------------------------------------------------------------------*/
|
||
|
||
/* 菜单初始化与反初始化 ---------------------------------------------------------------------------------------------*/
|
||
|
||
MenuErrCode menu_init(void)
|
||
{
|
||
return menu_core_init();
|
||
}
|
||
|
||
MenuErrCode menu_deinit(void)
|
||
{
|
||
return menu_core_deinit();
|
||
}
|
||
|
||
/* 菜单节点管理 -----------------------------------------------------------------------------------------------------*/
|
||
|
||
MenuNodeId menu_register_node(MenuNodeId node_id, MenuNodeId parent_id, const char* name, MenuCallback enter_cb, MenuCallback exit_cb)
|
||
{
|
||
// 参数验证
|
||
if (name == NULL) {
|
||
return 0; // 保持原有API兼容,0表示注册失败
|
||
}
|
||
|
||
// 调用核心层的节点注册功能
|
||
return menu_core_register_node(node_id, parent_id, name, enter_cb, exit_cb);
|
||
}
|
||
|
||
MenuErrCode menu_register_nodes(const struct MenuNode* nodes, uint16_t count)
|
||
{
|
||
// 暂未实现批量注册功能
|
||
(void)nodes;
|
||
(void)count;
|
||
return MENU_ERR_OPERATION_FAILED;
|
||
}
|
||
|
||
MenuErrCode menu_unregister_node(MenuNodeId node_id)
|
||
{
|
||
// 调用核心层的节点注销功能
|
||
return menu_core_unregister_node(node_id);
|
||
}
|
||
|
||
MenuErrCode menu_update_node(MenuNodeId node_id, const char* name, MenuCallback enter_cb, MenuCallback exit_cb)
|
||
{
|
||
MenuCoreCtx* core_ctx = menu_get_core_ctx();
|
||
MenuNode* node = menu_hash_find(core_ctx, node_id);
|
||
|
||
if (node == NULL || !node->flags.is_registered) {
|
||
return MENU_ERR_NODE_NOT_FOUND;
|
||
}
|
||
|
||
// 更新节点信息
|
||
if (name != NULL) {
|
||
node->name = name;
|
||
}
|
||
|
||
if (enter_cb != NULL) {
|
||
node->enter_cb = enter_cb;
|
||
}
|
||
|
||
if (exit_cb != NULL) {
|
||
node->exit_cb = exit_cb;
|
||
}
|
||
|
||
return MENU_ERR_OK;
|
||
}
|
||
|
||
const struct MenuNode* menu_find_node(MenuNodeId node_id)
|
||
{
|
||
MenuCoreCtx* core_ctx = menu_get_core_ctx();
|
||
return menu_hash_find(core_ctx, node_id);
|
||
}
|
||
|
||
/* 菜单事件处理 -----------------------------------------------------------------------------------------------------*/
|
||
|
||
MenuErrCode menu_post_event(MenuEventType event_type, uint8_t priority)
|
||
{
|
||
MenuCoreCtx* core_ctx = menu_get_core_ctx();
|
||
MenuEvent event;
|
||
|
||
event.type = event_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);
|
||
}
|
||
|
||
MenuErrCode menu_post_event_with_data(MenuEventType event_type, uint8_t priority, void* data)
|
||
{
|
||
MenuCoreCtx* core_ctx = menu_get_core_ctx();
|
||
MenuEvent event;
|
||
|
||
event.type = event_type;
|
||
event.priority = priority;
|
||
event.target_node_id = core_ctx->current_node_id;
|
||
event.data = data;
|
||
event.timestamp = core_ctx->last_refresh_tick;
|
||
|
||
return menu_event_queue_push(&core_ctx->event_queue, &event);
|
||
}
|
||
|
||
/* 菜单导航操作 -----------------------------------------------------------------------------------------------------*/
|
||
|
||
MenuErrCode menu_main_loop(uint32_t tick)
|
||
{
|
||
// 调用核心层的主循环功能
|
||
return menu_core_main_loop(tick);
|
||
}
|
||
|
||
MenuErrCode menu_enter(void)
|
||
{
|
||
return menu_post_event(MENU_EVENT_KEY_ENTER, 1);
|
||
}
|
||
|
||
MenuErrCode menu_exit(void)
|
||
{
|
||
return menu_post_event(MENU_EVENT_KEY_ESC, 1);
|
||
}
|
||
|
||
MenuErrCode menu_up(void)
|
||
{
|
||
return menu_post_event(MENU_EVENT_KEY_UP, 1);
|
||
}
|
||
|
||
MenuErrCode menu_down(void)
|
||
{
|
||
return menu_post_event(MENU_EVENT_KEY_DOWN, 1);
|
||
}
|
||
|
||
MenuErrCode menu_select(MenuNodeId node_id)
|
||
{
|
||
// 暂未实现直接选择指定节点功能
|
||
(void)node_id;
|
||
return MENU_ERR_OPERATION_FAILED;
|
||
}
|
||
|
||
MenuErrCode menu_reset(void)
|
||
{
|
||
// 暂未实现重置功能
|
||
return MENU_ERR_OPERATION_FAILED;
|
||
}
|
||
|
||
/* 菜单状态查询 -----------------------------------------------------------------------------------------------------*/
|
||
|
||
MenuState menu_get_state(void)
|
||
{
|
||
return menu_get_current_state();
|
||
}
|
||
|
||
MenuNodeId menu_get_current_node(void)
|
||
{
|
||
return menu_get_current_node_id();
|
||
}
|
||
|
||
uint8_t menu_get_nav_depth(void)
|
||
{
|
||
MenuCoreCtx* core_ctx = menu_get_core_ctx();
|
||
return core_ctx->nav_path.depth;
|
||
}
|
||
|
||
uint8_t menu_get_nav_path(MenuNodeId* path, uint8_t max_depth)
|
||
{
|
||
MenuCoreCtx* core_ctx = menu_get_core_ctx();
|
||
uint8_t actual_depth = core_ctx->nav_path.depth;
|
||
|
||
if (actual_depth > max_depth) {
|
||
actual_depth = max_depth;
|
||
}
|
||
|
||
for (uint8_t i = 0; i < actual_depth; i++) {
|
||
path[i] = core_ctx->nav_path.path[i];
|
||
}
|
||
|
||
return actual_depth;
|
||
}
|
||
|
||
/* 状态机扩展接口 ---------------------------------------------------------------------------------------------------*/
|
||
|
||
#if MENU_CONFIG_ENABLE_STATE_MACHINE_EXT
|
||
MenuErrCode menu_state_register_transition(const MenuStateTransition* transition)
|
||
{
|
||
MenuCoreCtx* core_ctx = menu_get_core_ctx();
|
||
|
||
if (core_ctx->custom_transition_count >= MENU_CONFIG_MAX_STATE_TRANSITIONS) {
|
||
return MENU_ERR_OUT_OF_MEMORY;
|
||
}
|
||
|
||
core_ctx->custom_transitions[core_ctx->custom_transition_count] = *transition;
|
||
core_ctx->custom_transition_count++;
|
||
|
||
return MENU_ERR_OK;
|
||
}
|
||
|
||
MenuErrCode menu_state_unregister_transition(MenuState current_state, MenuEventType event)
|
||
{
|
||
MenuCoreCtx* core_ctx = menu_get_core_ctx();
|
||
bool found = false;
|
||
|
||
// 查找并删除匹配的状态转换规则
|
||
for (uint16_t i = 0; i < core_ctx->custom_transition_count; i++) {
|
||
if (core_ctx->custom_transitions[i].current_state == current_state &&
|
||
core_ctx->custom_transitions[i].event == event) {
|
||
// 找到匹配的规则,将后续规则前移
|
||
for (uint16_t j = i; j < core_ctx->custom_transition_count - 1; j++) {
|
||
core_ctx->custom_transitions[j] = core_ctx->custom_transitions[j + 1];
|
||
}
|
||
core_ctx->custom_transition_count--;
|
||
found = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return found ? MENU_ERR_OK : MENU_ERR_INVALID_STATE;
|
||
}
|
||
|
||
MenuErrCode menu_state_switch(MenuState state)
|
||
{
|
||
MenuCoreCtx* core_ctx = menu_get_core_ctx();
|
||
core_ctx->current_state = state;
|
||
return MENU_ERR_OK;
|
||
}
|
||
#endif
|
||
|
||
/* 内存监控接口 -----------------------------------------------------------------------------------------------------*/
|
||
|
||
#if MENU_CONFIG_ENABLE_MEM_MONITOR
|
||
uint16_t menu_mem_get_used_nodes(void)
|
||
{
|
||
MenuCoreCtx* core_ctx = menu_get_core_ctx();
|
||
return core_ctx->node_count;
|
||
}
|
||
|
||
uint16_t menu_mem_get_free_nodes(void)
|
||
{
|
||
MenuCoreCtx* core_ctx = menu_get_core_ctx();
|
||
return core_ctx->free_node_count;
|
||
}
|
||
|
||
uint16_t menu_mem_get_max_nodes(void)
|
||
{
|
||
return MENU_CONFIG_MAX_NODES;
|
||
}
|
||
#endif
|
||
|