🧩 MENU_LIB — Architecture Overview¶
This document describes the internal architecture of the MENU_LIB library, its layered structure, data model, and how it integrates with user-generated menu files (menu.c, menu.h) and the display driver interface.
The Menu Library (MENU_LIB) provides a hierarchical, text-based menu system for embedded applications, separating menu logic, display handling, and menu data structures for portability across different display drivers (LCD, OLED, UART, etc.).
🏗️ Layered Architecture Overview¶
The library is designed with a 4-layer modular architecture, separating:
- Application Layer – user code and callbacks
- Menu Definition Layer – statically generated menu data (
menu.c,menu.h) - Menu Engine Core – logic, navigation, and rendering (
menu_lib) - Display Driver Layer – hardware abstraction (
menu_screen_driver_interface)
🔶 High-Level Dependency Diagram¶
graph TD
A[Application Layer]
B[Menu Definition Layer menu.c / menu.h]
C[MENU_LIB Core Engine menu_lib]
D[Display Driver Interface Layer]
A -->|uses| B
B -->|provides data to| C
C -->|depends on| D
🧱 Core Components¶
1. menu_t Structure (Menu Model)¶
Defined in menu_lib_type.h:
typedef struct menu_t {
const char *name;
struct menu_t *next;
struct menu_t *prev;
struct menu_t *child;
struct menu_t *parent;
void (*callback)(void);
} menu_t;
- Forms the tree of doubly linked lists used by the engine.
- Each node (menu item) can point to sibling items (
next,prev), a submenu (child), or a parent (parent). callbackis optional and executed when the item is entered.
2. Core Logic Layer (menu_lib.c)¶
Implements the main logic:
| Function | Purpose |
|---|---|
menu_init() |
Initialize internal state and assign driver |
menu_view_init() |
Set initial menu view and render root |
menu_next() / menu_prev() |
Horizontal navigation |
menu_enter() / menu_esc() |
Vertical navigation or callback execution |
update_screen_view() |
Refresh display via driver |
get_current_menu_position() |
Retrieve pointer to the current menu item |
This layer:
* Keeps track of the current menu pointer and navigation indices.
Ensures safe transitions (checks for NULL pointers).
Requests screen updates via the driver interface.
Simplified Flow¶
sequenceDiagram
participant App as Application
participant Core as MENU_LIB Core Engine
participant Disp as Display Driver
App->>Core: menu_next()
Core->>Core: update current_menu_pointer
Core->>Core: update_screen_view()
Core->>Disp: redraw visible items
3. Display Driver Interface Layer¶
Defined in menu_screen_driver_interface.h.
- Acts as a bridge between the logical menu engine and the actual display hardware.
- User implements driver functions for their specific hardware.
Example Connection¶
menu_screen_driver_interface_struct display_driver = {
.screen_init = lcd_init,
.clr_scr = lcd_clear,
.cursor_position = lcd_set_cursor,
.print_string = lcd_print,
.print_char = lcd_putc,
.get_number_of_screen_lines = lcd_rows,
.get_number_of_chars_per_line = lcd_cols
};
menu_init(&display_driver);
4. Menu Definition Layer (Generated Code)¶
Static menu structure is generated by JS Menu Designer.
menu.h— external declarations and configuration constants (e.g.MAX_MENU_DEPTH)menu.c— definitions ofmenu_titems and optional callbacks
Mermaid Diagram¶
graph TD
M[menu.c / menu.h] --> E[MENU_LIB Core Engine]
E --> D[Display Driver Interface]
5. Application Layer¶
The user's code:
- Initializes the system and the driver
- Calls
menu_init()andmenu_view_init() - Responds to hardware input (buttons, encoder, UART commands)
- Implements user callbacks
Example¶
void callback_settings(void) {
printf("Entering settings...\n");
}
int main(void) {
menu_init(&display_driver);
menu_view_init(&main_menu, on_exit, "Main Menu");
while (1) {
// Handle input and navigation
}
}
6. Callback Integration¶
The library supports a top-level exit callback (menu_exit_cb_t), defined in menu_lib.h.
It is invoked when the user exits the main menu via menu_esc() at the root level, allowing the application to restore context or perform cleanup.
🧭 Data Flow Diagram¶
flowchart TD
App[Application Layer] -->|uses| Core[MENU_LIB Core Engine]
Core -->|reads| Menu[Menu Definition Layer]
Core -->|calls| Driver[Display Driver Interface]
⚙️ File Responsibility Summary¶
| File | Role | Owned by |
|---|---|---|
| menu_lib.h / .c | Core engine | Library |
| menu_lib_type.h | Data types (menu_t, menu_status_t) |
Library |
| menu_screen_driver_interface.h | Abstract screen interface | Library |
| menu.h / menu.c | Static menu definitions & callbacks | Generated by JS tool |
| main.c | User application | User |
| lcd_driver.c/h | Hardware display driver | User |
🧠 Global State Management¶
graph TD
A[menu_level] -->|tracks depth| B[current_menu_pointer]
B --> C[menu_item_2_print]
A --> D[cursor_selection_menu_index]
A --> E[cursor_row_position]
| Variable | Description |
|---|---|
menu_level |
Current depth in menu hierarchy. |
current_menu_pointer |
Pointer to currently selected menu item. |
menu_item_2_print |
Pointer used for iterating through visible items. |
cursor_selection_menu_index[] |
Stores cursor position per menu depth. |
cursor_row_position[] |
Screen row where cursor is drawn per level. |
menu_initialized |
Indicates whether the library was successfully initialized. |
🔗 Display Abstraction¶
The display driver abstraction enables the menu to run on any screen implementation that adheres to the menu_screen_driver_interface_struct interface.
classDiagram
class menu_screen_driver_interface_struct {
+screen_init()
+clr_scr()
+cursor_position(row, column)
+print_string(string)
+print_char(character)
+get_number_of_screen_lines()
+get_number_of_chars_per_line()
}
class menu_lib {
+menu_init()
+menu_view_init()
+menu_next()
+menu_prev()
+menu_enter()
+menu_esc()
+update_screen_view()
}
menu_lib --> menu_screen_driver_interface_struct : uses
⚠️ Error Handling Flow¶
flowchart TD
A[Start] --> B[menu_init]
B -->|DISPLAY == NULL| E[MENU_ERR_NO_DISPLAY_INTERFACE]
B -->|Incomplete interface| F[MENU_ERR_INCOMPLETE_INTERFACE]
B -->|OK| C[menu_view_init]
C -->|Root == NULL| G[MENU_ERR_NO_MENU]
C -->|Depth > MAX_MENU_DEPTH| H[MENU_ERR_MENU_TOO_DEEP]
C -->|OK| I[Normal Operation]
🔐 Key Design Principles¶
- Static Memory Model — all menus defined at compile time; no dynamic allocation.
- Hardware Independence — rendering separated via driver interface.
- Callback-Driven Logic — menu items execute user-defined actions.
- Low Resource Usage — suitable for embedded targets.
- Separation of Concerns — menu logic, hardware, and application are independent layers.
🧩 Summary¶
The architecture of MENU_LIB ensures:
- Clear separation between logic, menu data, and hardware access.
- Safe, static handling of menu structures.
- Support for multiple hierarchical levels.
- Portable and lightweight embedded integration.