Files
menu/demo/demo.c
2025-12-19 17:01:27 +08:00

681 lines
23 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.

/**
**********************************************************************************************************************
* @file demo.c
* @brief 菜单组件示例程序 - 多语言版本
* @author menu_component
* @date 2025-12-19
**********************************************************************************************************************
*/
#include "../api/menu_api.h"
#include "../port/menu_port.h"
#include "language.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if defined(_WIN32) || defined(_WIN64)
#include <conio.h>
#define NON_BLOCKING_GETCHAR() _getch()
#define IS_KEY_AVAILABLE() _kbhit()
#else
#include <sys/time.h>
#include <sys/select.h>
#include <unistd.h>
#include <termios.h>
// 保存原始终端设置
static struct termios sg_original_termios;
/**
* @brief 设置终端为无缓冲模式
*/
static void set_nonblocking_terminal(void)
{
struct termios new_termios;
tcgetattr(STDIN_FILENO, &sg_original_termios);
new_termios = sg_original_termios;
new_termios.c_lflag &= ~(ICANON | ECHO); // 关闭行缓冲和回显
new_termios.c_cc[VMIN] = 1; // 至少读取1个字符
new_termios.c_cc[VTIME] = 0; // 无超时
tcsetattr(STDIN_FILENO, TCSANOW, &new_termios);
}
/**
* @brief 恢复终端为原始模式
*/
static void restore_terminal(void)
{
tcsetattr(STDIN_FILENO, TCSANOW, &sg_original_termios);
}
/**
* @brief 检查是否有按键输入
*/
static bool IS_KEY_AVAILABLE(void)
{
struct timeval tv;
fd_set fds;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
return select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv) > 0;
}
/**
* @brief 无缓冲获取按键
*/
static char NON_BLOCKING_GETCHAR(void)
{
return getchar();
}
#endif
/* 使用新的菜单节点ID枚举 */
#define MENU_ID_MAIN MENU_NODE_ID_MAIN
#define MENU_ID_ITEM1 MENU_NODE_ID_MEASUREMENT
#define MENU_ID_ITEM2 MENU_NODE_ID_PROTECTION
#define MENU_ID_ITEM3 MENU_NODE_ID_CONTROL
#define MENU_ID_SUB1 MENU_NODE_ID_SETTING
#define MENU_ID_SUB2 MENU_NODE_ID_RECORD
#define MENU_ID_LANGUAGE MENU_NODE_ID_HELP
#define MENU_ID_GRANDCHILD1 MENU_NODE_ID_ABOUT
#define MENU_ID_GRANDCHILD2 (MENU_NODE_ID_ABOUT + 1)
/* 测量菜单子项 */
#define MENU_ID_MEASUREMENT_VOLTAGE MENU_NODE_ID_MEASUREMENT_VOLTAGE
#define MENU_ID_MEASUREMENT_CURRENT MENU_NODE_ID_MEASUREMENT_CURRENT
#define MENU_ID_MEASUREMENT_POWER MENU_NODE_ID_MEASUREMENT_POWER
#define MENU_ID_MEASUREMENT_ENERGY MENU_NODE_ID_MEASUREMENT_ENERGY
#define MENU_ID_MEASUREMENT_FREQUENCY MENU_NODE_ID_MEASUREMENT_FREQUENCY
#define MENU_ID_MEASUREMENT_TEMPERATURE MENU_NODE_ID_MEASUREMENT_TEMPERATURE
/* 保护菜单子项 */
#define MENU_ID_PROTECTION_OVER_VOLTAGE MENU_NODE_ID_PROTECTION_OVER_VOLTAGE
#define MENU_ID_PROTECTION_UNDER_VOLTAGE MENU_NODE_ID_PROTECTION_UNDER_VOLTAGE
#define MENU_ID_PROTECTION_OVER_CURRENT MENU_NODE_ID_PROTECTION_OVER_CURRENT
#define MENU_ID_PROTECTION_SETTING MENU_NODE_ID_PROTECTION_SETTING
/* 控制菜单子项 */
#define MENU_ID_CONTROL_ON_OFF MENU_NODE_ID_CONTROL_ON_OFF
#define MENU_ID_CONTROL_START_STOP MENU_NODE_ID_CONTROL_START_STOP
#define MENU_ID_CONTROL_AUTO_MANUAL MENU_NODE_ID_CONTROL_AUTO_MANUAL
/* 设置菜单子项 */
#define MENU_ID_SETTING_LANGUAGE MENU_NODE_ID_SETTING_LANGUAGE
/* 持久化函数声明 */
static MenuErrCode demo_persistence_save(const uint8_t* data, uint16_t size);
static MenuErrCode demo_persistence_restore(uint8_t* data, uint16_t* size);
/* 全局变量 */
static uint32_t sg_tick = 0;
static bool sg_is_menu_active = false;
static SystemLang_e sg_current_language = SYSTEM_LANG_CHINESE;
/* 菜单回调函数 */
/**
* @brief 主菜单进入回调
*/
static MenuErrCode menu_enter_main(MenuNodeId node_id, struct MenuCoreCtx* core_ctx)
{
(void)node_id;
(void)core_ctx;
sg_is_menu_active = true;
printf("%s: %s\n", get_text(TEXT_ENTER), get_text(TEXT_MAIN_MENU));
return MENU_ERR_OK;
}
/**
* @brief 主菜单退出回调
*/
static MenuErrCode menu_exit_main(MenuNodeId node_id, struct MenuCoreCtx* core_ctx)
{
(void)node_id;
(void)core_ctx;
sg_is_menu_active = false;
printf("%s: %s\n", get_text(TEXT_EXIT), get_text(TEXT_MAIN_MENU));
return MENU_ERR_OK;
}
/**
* @brief 测量菜单进入回调
*/
static MenuErrCode menu_enter_item1(MenuNodeId node_id, struct MenuCoreCtx* core_ctx)
{
(void)node_id;
(void)core_ctx;
printf("%s: %s\n", get_text(TEXT_ENTER), get_text(TEXT_MAIN_MEASUREMENT));
return MENU_ERR_OK;
}
/**
* @brief 保护菜单进入回调
*/
static MenuErrCode menu_enter_item2(MenuNodeId node_id, struct MenuCoreCtx* core_ctx)
{
(void)node_id;
(void)core_ctx;
printf("%s: %s\n", get_text(TEXT_ENTER), get_text(TEXT_MAIN_PROTECTION));
return MENU_ERR_OK;
}
/**
* @brief 控制菜单进入回调
*/
static MenuErrCode menu_enter_item3(MenuNodeId node_id, struct MenuCoreCtx* core_ctx)
{
(void)node_id;
(void)core_ctx;
printf("%s: %s\n", get_text(TEXT_ENTER), get_text(TEXT_MAIN_CONTROL));
return MENU_ERR_OK;
}
/**
* @brief 语言设置进入回调(声明)
*/
static MenuErrCode menu_enter_language(MenuNodeId node_id, struct MenuCoreCtx* core_ctx);
/**
* @brief 设置菜单进入回调(声明)
*/
static MenuErrCode menu_enter_setting(MenuNodeId node_id, struct MenuCoreCtx* core_ctx);
/**
* @brief 重新注册菜单节点,用于语言切换
*/
static void re_register_menu_nodes(void)
{
// 先注销所有节点
menu_deinit();
menu_init();
// 主菜单
MenuNodeId main_node_id = menu_register_node(0, 0, get_text(TEXT_MAIN_MENU), menu_enter_main, menu_exit_main);
// 菜单项
MenuNodeId item1_node_id = menu_register_node(0, main_node_id, get_text(TEXT_MAIN_MEASUREMENT), menu_enter_item1, NULL);
MenuNodeId item2_node_id = menu_register_node(0, main_node_id, get_text(TEXT_MAIN_PROTECTION), menu_enter_item2, NULL);
MenuNodeId item3_node_id = menu_register_node(0, main_node_id, get_text(TEXT_MAIN_CONTROL), menu_enter_item3, NULL);
MenuNodeId sub1_node_id = menu_register_node(0, main_node_id, get_text(TEXT_MAIN_SETTING), menu_enter_setting, NULL);
// 测量菜单子项
menu_register_node(0, item1_node_id, get_text(TEXT_MEASURE_VOLTAGE), NULL, NULL);
menu_register_node(0, item1_node_id, get_text(TEXT_MEASURE_CURRENT), NULL, NULL);
menu_register_node(0, item1_node_id, get_text(TEXT_MEASURE_POWER), NULL, NULL);
menu_register_node(0, item1_node_id, get_text(TEXT_MEASURE_ENERGY), NULL, NULL);
menu_register_node(0, item1_node_id, get_text(TEXT_MEASURE_FREQUENCY), NULL, NULL);
menu_register_node(0, item1_node_id, get_text(TEXT_MEASURE_TEMPERATURE), NULL, NULL);
// 保护菜单子项
menu_register_node(0, item2_node_id, get_text(TEXT_PROTECT_OVER_VOLTAGE), NULL, NULL);
menu_register_node(0, item2_node_id, get_text(TEXT_PROTECT_UNDER_VOLTAGE), NULL, NULL);
menu_register_node(0, item2_node_id, get_text(TEXT_PROTECT_OVER_CURRENT), NULL, NULL);
menu_register_node(0, item2_node_id, get_text(TEXT_PROTECT_SETTING), NULL, NULL);
// 控制菜单子项
menu_register_node(0, item3_node_id, get_text(TEXT_CONTROL_ON_OFF), NULL, NULL);
menu_register_node(0, item3_node_id, get_text(TEXT_CONTROL_START_STOP), NULL, NULL);
menu_register_node(0, item3_node_id, get_text(TEXT_CONTROL_AUTO_MANUAL), NULL, NULL);
// 设置菜单子项
menu_register_node(0, sub1_node_id, get_text(TEXT_SETTING_LANGUAGE), menu_enter_language, NULL);
// 重新注册持久化回调函数
menu_persistence_register_callback(demo_persistence_save, demo_persistence_restore);
}
/**
* @brief 设置菜单进入回调
*/
static MenuErrCode menu_enter_setting(MenuNodeId node_id, struct MenuCoreCtx* core_ctx)
{
(void)node_id;
(void)core_ctx;
printf("%s: %s\n", get_text(TEXT_ENTER), get_text(TEXT_MAIN_SETTING));
return MENU_ERR_OK;
}
/**
* @brief 语言设置进入回调
*/
static MenuErrCode menu_enter_language(MenuNodeId node_id, struct MenuCoreCtx* core_ctx)
{
(void)node_id;
(void)core_ctx;
printf("%s: %s\n", get_text(TEXT_ENTER), get_text(TEXT_SETTING_LANGUAGE));
// 切换语言
if (sg_current_language == SYSTEM_LANG_CHINESE)
{
sg_current_language = SYSTEM_LANG_ENGLISH;
set_language(SYSTEM_LANG_ENGLISH);
printf("%s: English\n", get_text(TEXT_SETTING_LANGUAGE));
}
else
{
sg_current_language = SYSTEM_LANG_CHINESE;
set_language(SYSTEM_LANG_CHINESE);
printf("%s: 中文\n", get_text(TEXT_SETTING_LANGUAGE));
}
// 重新注册菜单节点,更新菜单名称
re_register_menu_nodes();
return MENU_ERR_OK;
}
/**
* @brief 默认获取系统时间函数
*/
static uint32_t demo_get_tick(void)
{
return sg_tick++;
}
/**
* @brief 默认打印函数
*/
static void demo_printf(const char* fmt, va_list args)
{
vprintf(fmt, args);
}
/**
* @brief 持久化数据保存回调函数
* @param data 要保存的数据
* @param size 数据大小
* @return 错误码
*/
static MenuErrCode demo_persistence_save(const uint8_t* data, uint16_t size)
{
FILE* fp = NULL;
MenuErrCode ret = MENU_ERR_OK;
// 打开文件进行写入
fp = fopen("menu_persistence.dat", "wb");
if (fp == NULL) {
printf("%s: %s\n", get_text(TEXT_ERROR), "打开文件失败");
return MENU_ERR_OPERATION_FAILED;
}
// 写入数据
if (fwrite(data, 1, size, fp) != size) {
printf("%s: %s\n", get_text(TEXT_ERROR), "写入文件失败");
ret = MENU_ERR_OPERATION_FAILED;
}
// 关闭文件
fclose(fp);
return ret;
}
/**
* @brief 持久化数据恢复回调函数
* @param data 恢复数据缓冲区
* @param size 数据大小
* @return 错误码
*/
static MenuErrCode demo_persistence_restore(uint8_t* data, uint16_t* size)
{
FILE* fp = NULL;
MenuErrCode ret = MENU_ERR_OK;
size_t read_size = 0;
// 打开文件进行读取
fp = fopen("menu_persistence.dat", "rb");
if (fp == NULL) {
printf("%s: %s\n", get_text(TEXT_WARNING), "文件不存在,使用默认设置");
return MENU_ERR_OPERATION_FAILED;
}
// 获取文件大小
fseek(fp, 0, SEEK_END);
read_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
// 检查文件大小是否合法
if (read_size > *size) {
printf("%s: %s\n", get_text(TEXT_ERROR), "文件过大");
fclose(fp);
return MENU_ERR_INVALID_PARAM;
}
// 读取数据
if (fread(data, 1, read_size, fp) != read_size) {
printf("%s: %s\n", get_text(TEXT_ERROR), "读取文件失败");
ret = MENU_ERR_OPERATION_FAILED;
} else {
// 更新实际读取的大小
*size = (uint16_t)read_size;
}
// 关闭文件
fclose(fp);
return ret;
}
/**
* @brief 硬件驱动配置
*/
static MenuPortDriver sg_demo_driver = {
.printf = demo_printf,
.get_tick = demo_get_tick,
.delay_ms = NULL,
.display = NULL,
.key_scan = NULL,
.irq_ctrl = NULL,
.error_handler = NULL,
.modbus_send = NULL,
.modbus_receive = NULL,
.persistence_save = demo_persistence_save,
.persistence_restore = demo_persistence_restore,
};
/**
* @brief 演示菜单导航
*/
/**
* @brief 显示当前菜单的子菜单项
*/
static void display_menu_items(void)
{
MenuNodeId curr_node_id = menu_get_current_node();
const MenuNode* curr_node = menu_find_node(curr_node_id);
if (curr_node == NULL) {
printf("\n无效节点\n");
return;
}
// 清屏(可选,根据终端支持情况)
printf("\033[2J\033[H");
// 显示当前菜单路径
printf("%s\n", get_text(TEXT_MAIN_MENU));
printf("==================\n");
// 显示当前菜单状态
printf("%s: %s\n", get_text(TEXT_CURRENT), curr_node->name ? curr_node->name : "Unnamed");
// 显示导航路径
uint8_t path_depth = menu_get_nav_depth();
MenuNodeId path[MENU_CONFIG_STACK_DEPTH];
menu_get_nav_path(path, MENU_CONFIG_STACK_DEPTH);
printf("%s: ", get_text(TEXT_STATUS));
for (uint8_t i = 0; i < path_depth; i++) {
const MenuNode* path_node = menu_find_node(path[i]);
if (path_node != NULL) {
printf("%s", path_node->name ? path_node->name : "Unnamed");
if (i < path_depth - 1) {
printf(" -> ");
}
}
}
printf("\n\n");
// 显示当前菜单的子菜单项
printf("%s:\n", get_text(TEXT_SUMMARY));
if (curr_node->first_child_id != 0) {
// 遍历所有子节点
const MenuNode* child_node = menu_find_node(curr_node->first_child_id);
uint8_t item_index = 1;
while (child_node != NULL) {
// 子菜单仅显示列表,不高亮选中项(高亮在同级节点中处理)
printf(" %d. %s\n", item_index, child_node->name ? child_node->name : "Unnamed");
MenuNodeId next_id = child_node->next_sibling_id;
if (next_id == 0) {
break;
}
child_node = menu_find_node(next_id);
item_index++;
}
} else {
printf(" %s\n", get_text(TEXT_EMPTY));
}
// 显示当前节点在同级节点中的位置
const MenuNode* parent_node = menu_find_node(curr_node->parent_id);
if (parent_node != NULL) {
printf("\n%s:\n", get_text(TEXT_CURRENT_SELECTION));
// 遍历所有兄弟节点
const MenuNode* sibling_node = menu_find_node(parent_node->first_child_id);
uint8_t item_index = 1;
while (sibling_node != NULL) {
// 检查当前显示的节点是否为选中节点
bool is_selected = (sibling_node->id == curr_node_id);
// 高亮显示当前选中的菜单项
if (is_selected) {
printf(" **> %d. %s <**\n",
item_index, sibling_node->name ? sibling_node->name : "Unnamed");
} else {
printf(" %d. %s\n", item_index, sibling_node->name ? sibling_node->name : "Unnamed");
}
MenuNodeId next_id = sibling_node->next_sibling_id;
if (next_id == 0) {
break;
}
sibling_node = menu_find_node(next_id);
item_index++;
}
}
// 显示菜单操作提示
printf("\n%s:\n", get_text(TEXT_OPERATIONS));
printf(" ↑/%s: %s\n", get_text(TEXT_DOWN_ARROW), get_text(TEXT_SELECT_ITEM));
printf(" %s: %s\n", get_text(TEXT_ENTER), get_text(TEXT_ENTER_SUBMENU));
printf(" Esc/%s: %s\n", get_text(TEXT_LEFT_ARROW), get_text(TEXT_RETURN_PARENT));
printf(" q: %s\n", get_text(TEXT_EXIT));
printf("==================\n");
}
/**
* @brief 演示菜单导航
*/
static void demo_menu_navigation(void)
{
char key = 0;
// 设置终端为无缓冲模式仅在非Windows平台
#ifndef _WIN32
set_nonblocking_terminal();
#endif
printf("\n%s\n", get_text(TEXT_MAIN_MENU));
printf("==================\n");
printf("%s: %s\n", get_text(TEXT_SELECT_OPTION), get_text(TEXT_MAIN_MENU));
printf("Enter: %s\n", get_text(TEXT_ENTER));
printf("Esc: %s\n", get_text(TEXT_EXIT));
printf("q: %s\n", get_text(TEXT_EXIT));
printf("%s: %s\n", get_text(TEXT_UP_ARROW), get_text(TEXT_SELECT_PREVIOUS));
printf("%s: %s\n", get_text(TEXT_DOWN_ARROW), get_text(TEXT_SELECT_NEXT));
printf("%s: %s\n", get_text(TEXT_RIGHT_ARROW), get_text(TEXT_ENTER_SUBMENU));
printf("%s: %s\n", get_text(TEXT_LEFT_ARROW), get_text(TEXT_RETURN_PARENT));
printf("==================\n");
// 初始化显示
display_menu_items();
while (1) {
// 持续处理菜单主循环,确保事件得到及时处理
menu_main_loop(demo_get_tick());
// 检查是否有按键输入
if (IS_KEY_AVAILABLE()) {
// 获取按键输入(无缓冲)
key = NON_BLOCKING_GETCHAR();
// 处理退出键
if (key == 'q' || key == 'Q') {
#ifndef _WIN32
restore_terminal();
#endif
return;
}
// 处理回车键
else if (key == '\n' || key == '\r') {
// 不管节点是否有子菜单,都处理回车事件
menu_post_event(MENU_EVENT_KEY_ENTER, 1);
// 处理菜单主循环
menu_main_loop(demo_get_tick());
// 显示当前菜单状态和菜单项
display_menu_items();
}
// 处理Esc键和箭头键
else if (key == '\x1B') {
// 读取完整的Esc序列
char esc_key = NON_BLOCKING_GETCHAR();
if (esc_key == '[') {
key = NON_BLOCKING_GETCHAR();
switch (key) {
case 'A': // 上箭头 - 选择上一项
menu_post_event(MENU_EVENT_KEY_UP, 1);
break;
case 'B': // 下箭头 - 选择下一项
menu_post_event(MENU_EVENT_KEY_DOWN, 1);
break;
case 'C': // 右箭头 - 进入子菜单
menu_post_event(MENU_EVENT_KEY_ENTER, 1);
break;
case 'D': // 左箭头 - 返回上一级菜单
menu_post_event(MENU_EVENT_KEY_ESC, 1);
break;
default:
break;
}
// 处理菜单主循环
menu_main_loop(demo_get_tick());
// 显示当前菜单状态和菜单项
display_menu_items();
} else {
// 单独的Esc键 - 返回上一级菜单
menu_post_event(MENU_EVENT_KEY_ESC, 1);
// 处理菜单主循环
menu_main_loop(demo_get_tick());
// 显示当前菜单状态和菜单项
display_menu_items();
}
}
// 处理普通字符输入
else {
// 可以根据需要添加其他字符处理逻辑
}
}
// 短延迟避免CPU占用过高
#ifdef _WIN32
Sleep(10);
#else
usleep(10000); // 10ms
#endif
}
}
/**
* @brief 主函数
*/
int main(int argc, char* argv[])
{
(void)argc;
(void)argv;
// 初始化多语言系统
set_language(SYSTEM_LANG_CHINESE);
printf("%s\n", get_text(TEXT_MAIN_MENU));
printf("==================\n");
// 初始化硬件端口层
menu_port_init(&sg_demo_driver);
// 初始化菜单组件
MenuErrCode err = menu_init();
if (err != MENU_ERR_OK) {
printf("%s\n", get_text(TEXT_TEST));
return EXIT_FAILURE;
}
// 注册菜单节点
// 主菜单
MenuNodeId main_node_id = menu_register_node(0, 0, get_text(TEXT_MAIN_MENU), menu_enter_main, menu_exit_main);
// 菜单项
MenuNodeId item1_node_id = menu_register_node(0, main_node_id, get_text(TEXT_MAIN_MEASUREMENT), menu_enter_item1, NULL);
MenuNodeId item2_node_id = menu_register_node(0, main_node_id, get_text(TEXT_MAIN_PROTECTION), menu_enter_item2, NULL);
MenuNodeId item3_node_id = menu_register_node(0, main_node_id, get_text(TEXT_MAIN_CONTROL), menu_enter_item3, NULL);
MenuNodeId sub1_node_id = menu_register_node(0, main_node_id, get_text(TEXT_MAIN_SETTING), menu_enter_setting, NULL);
// 测量菜单子项
menu_register_node(0, item1_node_id, get_text(TEXT_MEASURE_VOLTAGE), NULL, NULL);
menu_register_node(0, item1_node_id, get_text(TEXT_MEASURE_CURRENT), NULL, NULL);
menu_register_node(0, item1_node_id, get_text(TEXT_MEASURE_POWER), NULL, NULL);
menu_register_node(0, item1_node_id, get_text(TEXT_MEASURE_ENERGY), NULL, NULL);
menu_register_node(0, item1_node_id, get_text(TEXT_MEASURE_FREQUENCY), NULL, NULL);
menu_register_node(0, item1_node_id, get_text(TEXT_MEASURE_TEMPERATURE), NULL, NULL);
// 保护菜单子项
menu_register_node(0, item2_node_id, get_text(TEXT_PROTECT_OVER_VOLTAGE), NULL, NULL);
menu_register_node(0, item2_node_id, get_text(TEXT_PROTECT_UNDER_VOLTAGE), NULL, NULL);
menu_register_node(0, item2_node_id, get_text(TEXT_PROTECT_OVER_CURRENT), NULL, NULL);
menu_register_node(0, item2_node_id, get_text(TEXT_PROTECT_SETTING), NULL, NULL);
// 控制菜单子项
menu_register_node(0, item3_node_id, get_text(TEXT_CONTROL_ON_OFF), NULL, NULL);
menu_register_node(0, item3_node_id, get_text(TEXT_CONTROL_START_STOP), NULL, NULL);
menu_register_node(0, item3_node_id, get_text(TEXT_CONTROL_AUTO_MANUAL), NULL, NULL);
// 设置菜单子项
menu_register_node(0, sub1_node_id, get_text(TEXT_SETTING_LANGUAGE), menu_enter_language, NULL);
// 注册持久化回调函数
err = menu_persistence_register_callback(demo_persistence_save, demo_persistence_restore);
if (err != MENU_ERR_OK) {
printf("%s: %s\n", get_text(TEXT_ERROR), get_text(TEXT_REGISTER_CALLBACK_FAILED));
}
// 尝试恢复之前的菜单状态
err = menu_persistence_restore();
if (err == MENU_ERR_OK) {
printf("%s: %s\n", get_text(TEXT_SUCCESS), get_text(TEXT_RESTORE_MENU_STATE));
} else {
printf("%s: %s: Error %d\n", get_text(TEXT_ERROR), get_text(TEXT_RESTORE_MENU_STATE_FAILED), err);
printf("%s\n", get_text(TEXT_START_DEFAULT));
}
printf("%s\n", get_text(TEXT_TEST));
// 运行菜单演示
demo_menu_navigation();
// 保存当前菜单状态
err = menu_persistence_save();
if (err == MENU_ERR_OK) {
printf("%s: %s\n", get_text(TEXT_SUCCESS), get_text(TEXT_SAVE_MENU_STATE));
} else {
printf("%s: %s: Error %d\n", get_text(TEXT_ERROR), get_text(TEXT_SAVE_MENU_STATE_FAILED), err);
}
// 清理资源
menu_deinit();
menu_port_deinit();
printf("\n%s\n", get_text(TEXT_EXIT));
return EXIT_SUCCESS;
}