/** * @file menu.h * @brief 菜单组件对外暴露的核心接口(用户唯一需要包含的头文件) * @note 工业级嵌入式菜单组件 - 对外API层 */ #ifndef MENU_H #define MENU_H #include "menu_config.h" #include #include /************************** 全局类型导出 **************************/ /** * @brief 菜单错误码(工业级错误处理:明确所有可能的错误类型) */ typedef enum { MENU_OK = 0, ///< 操作成功 MENU_ERR_INVALID_PARAM, ///< 无效参数 MENU_ERR_OUT_OF_MEMORY, ///< 内存不足(静态内存池已满) MENU_ERR_NODE_NOT_FOUND, ///< 菜单节点未找到 MENU_ERR_STACK_OVERFLOW, ///< 菜单栈溢出(导航层级超过配置) MENU_ERR_STACK_UNDERFLOW, ///< 菜单栈下溢(已到根节点仍返回) MENU_ERR_EVENT_QUEUE_FULL, ///< 事件队列已满 MENU_ERR_NOT_SUPPORTED, ///< 功能未启用(如未开启多语言) MENU_ERR_HW_PORT_ERROR ///< 硬件端口层错误 } MenuErrCode; /** * @brief 菜单事件类型(事件驱动核心:解耦按键与菜单逻辑) */ typedef enum { MENU_EVENT_NONE = 0, ///< 无事件 MENU_EVENT_KEY_UP, ///< 上键按下 MENU_EVENT_KEY_DOWN, ///< 下键按下 MENU_EVENT_KEY_ENTER, ///< 确认键按下 MENU_EVENT_KEY_BACK, ///< 返回键按下 MENU_EVENT_CUSTOM_BEGIN = 0x10, ///< 自定义事件起始标识(用户可扩展) } MenuEventType; /** * @brief 菜单节点ID类型(统一标识) */ typedef uint16_t MenuNodeId; /** * @brief 菜单回调函数类型(菜单选中/退出时的执行逻辑) * @param node_id 触发回调的菜单节点ID * @return 错误码 */ typedef MenuErrCode (*MenuCallback)(MenuNodeId node_id); /************************** 核心接口声明 **************************/ /** * @brief 菜单组件初始化(必须首先调用) * @return 错误码 */ MenuErrCode menu_init(void); /** * @brief 菜单主循环(需在用户主循环中调用,处理事件和刷新显示) */ void menu_main_loop(void); /** * @brief 发送事件到菜单事件队列(如按键事件、自定义事件) * @param type 事件类型 * @param param 事件附加参数(可选,如按键长按时间) * @return 错误码 */ MenuErrCode menu_post_event(MenuEventType type, uint32_t param); /** * @brief 注册菜单节点(构建菜单树) * @param parent_id 父节点ID(根节点填0) * @param node_id 当前节点ID(唯一,不可重复) * @param name_str 菜单名称字符串(或多语言索引) * @param enter_cb 进入该菜单的回调函数(NULL表示无) * @param exit_cb 退出该菜单的回调函数(NULL表示无) * @return 错误码 */ MenuErrCode menu_register_node(MenuNodeId parent_id, MenuNodeId node_id, const char* name_str, MenuCallback enter_cb, MenuCallback exit_cb); /** * @brief 获取当前选中的菜单节点ID * @param node_id 输出参数,当前节点ID * @return 错误码 */ MenuErrCode menu_get_current_node(MenuNodeId* node_id); /************************** 功能扩展接口声明(可裁剪) **************************/ #if MENU_CONFIG_ENABLE_PARAM /** * @brief 参数类型枚举 */ typedef enum { MENU_PARAM_TYPE_INT8, MENU_PARAM_TYPE_UINT8, MENU_PARAM_TYPE_INT16, MENU_PARAM_TYPE_UINT16, MENU_PARAM_TYPE_INT32, MENU_PARAM_TYPE_UINT32, MENU_PARAM_TYPE_FLOAT, } MenuParamType; /** * @brief 注册参数到菜单节点(参数管理功能) * @param node_id 菜单节点ID(参数与菜单绑定) * @param param_id 参数ID(唯一) * @param type 参数类型 * @param min_val 最小值(浮点型,内部自动转换) * @param max_val 最大值(浮点型,内部自动转换) * @param default_val 默认值(浮点型,内部自动转换) * @param scale 缩放因子(如0.1表示保留1位小数) * @return 错误码 */ MenuErrCode menu_param_register(MenuNodeId node_id, uint16_t param_id, MenuParamType type, float min_val, float max_val, float default_val, float scale); /** * @brief 设置参数值 * @param param_id 参数ID * @param value 新值(浮点型,内部自动转换) * @return 错误码 */ MenuErrCode menu_param_set_value(uint16_t param_id, float value); /** * @brief 获取参数值 * @param param_id 参数ID * @param value 输出参数,当前值(浮点型) * @return 错误码 */ MenuErrCode menu_param_get_value(uint16_t param_id, float* value); /** * @brief 获取参数类型 * @param param_id 参数ID * @param type 输出参数,参数类型 * @return 错误码 */ MenuErrCode menu_param_get_type(uint16_t param_id, MenuParamType* type); #endif // MENU_CONFIG_ENABLE_PARAM #if MENU_CONFIG_ENABLE_LANG /** * @brief 设置当前语言 * @param lang_id 语言ID(如0-中文,1-英文) * @return 错误码 */ MenuErrCode menu_lang_set_current(uint8_t lang_id); /** * @brief 获取当前语言 * @param lang_id 输出参数,当前语言ID * @return 错误码 */ MenuErrCode menu_lang_get_current(uint8_t* lang_id); #endif // MENU_CONFIG_ENABLE_LANG /************************** Modbus映射功能(启用时有效) **************************/ #if MENU_CONFIG_ENABLE_MODBUS_MAP /** * @brief Modbus寄存器类型(符合Modbus协议标准) */ typedef enum { MODBUS_REG_TYPE_COIL = 0, ///< 线圈(1位,地址范围00001-09999) MODBUS_REG_TYPE_DISCRETE_INPUT, ///< 离散输入(1位,地址范围10001-19999) MODBUS_REG_TYPE_HOLDING_REG, ///< 保持寄存器(16位,地址范围40001-49999) MODBUS_REG_TYPE_INPUT_REG, ///< 输入寄存器(16位,地址范围30001-39999) } ModbusRegType; /** * @brief Modbus寄存器读写权限 */ typedef enum { MODBUS_PERM_READ_ONLY = 0, ///< 只读(如离散输入、输入寄存器) MODBUS_PERM_WRITE_ONLY, ///< 只写(如线圈) MODBUS_PERM_READ_WRITE, ///< 读写(如保持寄存器) } ModbusPerm; /** * @brief Modbus映射结构体(对外只读,内部初始化) */ typedef struct { uint16_t param_id; ///< 关联的参数ID ModbusRegType reg_type; ///< 寄存器类型 uint16_t reg_addr; ///< 寄存器起始地址(协议地址,如40001) uint8_t reg_count; ///< 占用寄存器数量(如32位浮点占2个16位寄存器) ModbusPerm perm; ///< 读写权限 uint8_t byte_order; ///< 字节序(0-小端,1-大端,2-Modbus标准) } ModbusMap; /** * @brief 注册参数与Modbus寄存器的映射关系 * @param param_id 参数ID(需已通过menu_param_register注册) * @param reg_type 寄存器类型 * @param reg_addr 寄存器起始地址(协议地址,如40001) * @param reg_count 占用寄存器数量(如1:16位,2:32位,4:64位) * @param perm 读写权限 * @param byte_order 字节序(可选,默认使用MENU_CONFIG_MODBUS_BYTE_ORDER) * @return 错误码 */ MenuErrCode menu_modbus_map_register(uint16_t param_id, ModbusRegType reg_type, uint16_t reg_addr, uint8_t reg_count, ModbusPerm perm, uint8_t byte_order); /** * @brief 根据参数ID查询Modbus映射关系 * @param param_id 参数ID * @param map 输出参数,映射关系结构体 * @return 错误码 */ MenuErrCode menu_modbus_map_query_by_param(uint16_t param_id, ModbusMap* map); /** * @brief 根据寄存器地址和类型查询Modbus映射关系 * @param reg_type 寄存器类型 * @param reg_addr 寄存器地址 * @param map 输出参数,映射关系结构体 * @return 错误码 */ MenuErrCode menu_modbus_map_query_by_reg(ModbusRegType reg_type, uint16_t reg_addr, ModbusMap* map); /** * @brief 将参数值写入对应的Modbus寄存器(双向转换:参数值→寄存器数据) * @param param_id 参数ID * @param reg_buf 输出参数,寄存器数据缓冲区(需足够大,如32位占2个16位寄存器) * @param buf_len 缓冲区长度(输入),实际写入长度(输出) * @return 错误码 */ MenuErrCode menu_modbus_map_param_to_reg(uint16_t param_id, uint8_t* reg_buf, uint8_t* buf_len); /** * @brief 将Modbus寄存器数据读取到参数值(双向转换:寄存器数据→参数值) * @param param_id 参数ID * @param reg_buf 输入参数,寄存器数据缓冲区 * @param buf_len 缓冲区长度 * @return 错误码 */ MenuErrCode menu_modbus_map_reg_to_param(uint16_t param_id, const uint8_t* reg_buf, uint8_t buf_len); #endif // MENU_CONFIG_ENABLE_MODBUS_MAP #endif // MENU_H