wip:
This commit is contained in:
@@ -1 +1 @@
|
||||
idf_component_register(SRCS "main.c" INCLUDE_DIRS "include")
|
||||
idf_component_register(SRCS "menu_manager.c" INCLUDE_DIRS "include")
|
||||
12
Kconfig
Normal file
12
Kconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
menu "Menu Menager"
|
||||
|
||||
config MAX_DEPTH_PATH
|
||||
int "Set max deth of submenus"
|
||||
default 5
|
||||
|
||||
config SALVE_INDEX
|
||||
bool "Savel last menu index selected"
|
||||
default y
|
||||
|
||||
endmenu
|
||||
|
||||
68
README.md
68
README.md
@@ -1,3 +1,67 @@
|
||||
# esp_component_template
|
||||
# Menu Manager
|
||||
Easy and flexible menu manager for ESP-IDF
|
||||
|
||||
|
||||
```mermaid
|
||||
---
|
||||
config:
|
||||
title: Menu Manager
|
||||
---
|
||||
flowchart TD
|
||||
start((menu init))
|
||||
createQueue[Create Queue qCommand]
|
||||
waitQueue[Wait Queue qCommand]
|
||||
showDisplay[Show menu]
|
||||
|
||||
funtionInExecution{Is there a funtion in execution?}
|
||||
isCommandBack{Is command back?}
|
||||
exitFuntion[Exit funtion in execution]
|
||||
|
||||
swithCasesInput{Command}
|
||||
navigateUP[Increments the index]
|
||||
navigateDOWN[Decrements the index]
|
||||
navigateBACK[return to parent menu]
|
||||
|
||||
navigateSELECTION{Is there a funtion?}
|
||||
selectSubMenu[Select sub menu]
|
||||
executeFuntion[Execute funtion]
|
||||
|
||||
start --> createQueue
|
||||
createQueue --> waitQueue
|
||||
waitQueue --> funtionInExecution
|
||||
funtionInExecution --"Yes"--> isCommandBack
|
||||
isCommandBack --"Yes"--> exitFuntion
|
||||
funtionInExecution --"No"--> swithCasesInput
|
||||
|
||||
swithCasesInput --"UP"--> navigateUP
|
||||
swithCasesInput --"DOWN"--> navigateDOWN
|
||||
swithCasesInput --"BACK"--> navigateBACK
|
||||
swithCasesInput --"SELECT"--> navigateSELECTION
|
||||
|
||||
exitFuntion --> showDisplay
|
||||
navigateUP --> showDisplay
|
||||
navigateDOWN --> showDisplay
|
||||
navigateBACK --> showDisplay
|
||||
|
||||
navigateSELECTION --"No"--> selectSubMenu --> showDisplay
|
||||
navigateSELECTION --"Yes"--> executeFuntion --> waitQueue
|
||||
|
||||
showDisplay --> waitQueue
|
||||
|
||||
%% Estilos e cores
|
||||
classDef startEnd fill:#e1f5fe,stroke:#01579b,stroke-width:3px,color:#000
|
||||
classDef queue fill:#f3e5f5,stroke:#4a148c,stroke-width:2px,color:#000
|
||||
classDef display fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px,color:#000
|
||||
classDef decision fill:#fff3e0,stroke:#e65100,stroke-width:2px,color:#000
|
||||
classDef navigation fill:#fce4ec,stroke:#ad1457,stroke-width:2px,color:#000
|
||||
classDef execution fill:#ffebee,stroke:#c62828,stroke-width:2px,color:#000
|
||||
classDef selection fill:#e0f2f1,stroke:#00695c,stroke-width:2px,color:#000
|
||||
|
||||
class start startEnd
|
||||
class createQueue,waitQueue queue
|
||||
class showDisplay display
|
||||
class funtionInExecution,isCommandBack,swithCasesInput,navigateSELECTION decision
|
||||
class navigateUP,navigateDOWN,navigateBACK navigation
|
||||
class exitFuntion,executeFuntion execution
|
||||
class selectSubMenu selection```
|
||||
|
||||
esp_component_template
|
||||
8
examples/default/CMakeLists.txt
Normal file
8
examples/default/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(main)
|
||||
2
examples/default/main/CMakeLists.txt
Normal file
2
examples/default/main/CMakeLists.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
6
examples/default/main/idf_component.yml
Normal file
6
examples/default/main/idf_component.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
dependencies:
|
||||
idf:
|
||||
version: '>=4.1.0'
|
||||
MarcioBulla/menu_manager:
|
||||
git: https://github.com/MarcioBulla/menu_manager
|
||||
version: main
|
||||
88
examples/default/main/main.c
Normal file
88
examples/default/main/main.c
Normal file
@@ -0,0 +1,88 @@
|
||||
#include "menu_manager.h"
|
||||
#include <esp_log.h>
|
||||
#include <esp_system.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <freertos/task.h>
|
||||
#include <sdkconfig.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
void dumb(void *args) {
|
||||
ESP_LOGI(TAG, "I am dumb");
|
||||
while (true) {
|
||||
vTaskDelay(10000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
menu_node_t submenu[3] = {
|
||||
{.label = "funcA", .function = &dumb},
|
||||
{.label = "funcB", .function = &dumb},
|
||||
{.label = "funcC", .function = &dumb},
|
||||
};
|
||||
|
||||
menu_node_t root = {
|
||||
.label = "root",
|
||||
.num_options = 3,
|
||||
.submenus = (menu_node_t[3]){
|
||||
{.label = "submenu1", .submenus = submenu, .num_options = 3},
|
||||
{.label = "submenu2", .submenus = submenu, .num_options = 3},
|
||||
{.label = "submenu3", .submenus = submenu, .num_options = 3},
|
||||
}};
|
||||
|
||||
void simula_input(void *args) {
|
||||
Navigate_t teste = NAVIGATE_UP;
|
||||
vTaskDelay(6000 / portTICK_PERIOD_MS);
|
||||
ESP_LOGI(TAG, "NEXT");
|
||||
xQueueSend(qCommands, &teste, portMAX_DELAY);
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
teste = NAVIGATE_SELECT;
|
||||
ESP_LOGI(TAG, "SELECT");
|
||||
xQueueSend(qCommands, &teste, portMAX_DELAY);
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
teste = NAVIGATE_DOWN;
|
||||
ESP_LOGI(TAG, "DOWN");
|
||||
xQueueSend(qCommands, &teste, portMAX_DELAY);
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
teste = NAVIGATE_SELECT;
|
||||
ESP_LOGI(TAG, "SELECT");
|
||||
xQueueSend(qCommands, &teste, portMAX_DELAY);
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
teste = NAVIGATE_BACK;
|
||||
ESP_LOGI(TAG, "BACK");
|
||||
xQueueSend(qCommands, &teste, portMAX_DELAY);
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
ESP_LOGI(TAG, "BACK");
|
||||
xQueueSend(qCommands, &teste, portMAX_DELAY);
|
||||
vTaskDelay(10000 / portTICK_PERIOD_MS);
|
||||
|
||||
ESP_LOGI(TAG, "Finalizada");
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void display(menu_path_t *current_path) {
|
||||
|
||||
ESP_LOGI(TAG, "title: %s, index_select: %d",
|
||||
current_path->current_menu->label, current_path->current_index);
|
||||
|
||||
ESP_LOGI(
|
||||
TAG, "Option Selected %s",
|
||||
current_path->current_menu->submenus[current_path->current_index].label);
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
|
||||
menu_config_t config = {
|
||||
.root = root,
|
||||
.loop = true,
|
||||
.display = &display,
|
||||
};
|
||||
|
||||
xTaskCreatePinnedToCore(&menu_init, "menu_init", 2048, &config, 3, NULL, 0);
|
||||
vTaskDelay(5000 / portMAX_DELAY);
|
||||
xTaskCreatePinnedToCore(&simula_input, "simula", 2048, NULL, 1, NULL, 0);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
113
include/menu_manager.h
Normal file
113
include/menu_manager.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* @file menu_manager.h
|
||||
* @brief This file defines structures and functions related to the Menu System.
|
||||
*/
|
||||
|
||||
#ifndef __MENU_MANAGER_H__
|
||||
#define __MENU_MANAGER_H__
|
||||
#pragma once
|
||||
#include "freertos/idf_additions.h"
|
||||
#include "sdkconfig.h"
|
||||
#include <esp_err.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define END_MENU_FUNCTION end_menuFunction()
|
||||
#define SET_QUICK_FUNCTION setQuick_menuFunction()
|
||||
|
||||
extern TaskHandle_t tMenuFunction;
|
||||
extern QueueHandle_t qCommands;
|
||||
|
||||
/**
|
||||
* Type with possibles of action in menu system.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
NAVIGATE_UP,
|
||||
/**< Action up (index++). */
|
||||
NAVIGATE_DOWN,
|
||||
/**< Action DOWN (index--). */
|
||||
NAVIGATE_SELECT,
|
||||
/**< Action SELECT (depth++). */
|
||||
NAVIGATE_BACK,
|
||||
/**< Action BACH (depth--). */
|
||||
NAVIGATE_NOTHING,
|
||||
/**< Nothing. */
|
||||
} Navigate_t;
|
||||
|
||||
/**
|
||||
* Menu System is based in nodes all menus are nodes. Submenus are nodes with
|
||||
* array of more submenus and function (leafs) are nodes with function.
|
||||
*
|
||||
*/
|
||||
typedef struct menu_node {
|
||||
char *label;
|
||||
/**< Title of node. */
|
||||
struct menu_node *submenus;
|
||||
/**< Point of array submenus or one submenu. */
|
||||
size_t num_options;
|
||||
/**< number of option on submenu. */
|
||||
void (*function)(void *args);
|
||||
/**< function that defined this node as leaf. */
|
||||
} menu_node_t;
|
||||
|
||||
/**
|
||||
* Struct for save location and index.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
menu_node_t *current_menu;
|
||||
/**< Point if current menu. */
|
||||
uint8_t current_index;
|
||||
/**< current Index of selected option. */
|
||||
} menu_path_t;
|
||||
|
||||
/**
|
||||
* This struct is all essential args that menu_init will need.
|
||||
*/
|
||||
typedef struct {
|
||||
menu_node_t root;
|
||||
/**< Menu_node_t: origin of Menu System. */
|
||||
void (*display)(menu_path_t *current_path);
|
||||
/**< Function that receive menu_path_t and index for display current
|
||||
* selection. */
|
||||
bool loop;
|
||||
/**< Loop menu. */
|
||||
} menu_config_t;
|
||||
|
||||
/**
|
||||
* Start menu system that receive generic input function and generic
|
||||
* display function.
|
||||
*
|
||||
* @param params The struct that there are args.
|
||||
*/
|
||||
void menu_init(void *params);
|
||||
|
||||
/**
|
||||
* @brief Use this function all option menus when finish
|
||||
*/
|
||||
void exitFunction(void);
|
||||
|
||||
/**
|
||||
* @brief Exec especific funtioon
|
||||
*
|
||||
* @param Function addres of function
|
||||
*/
|
||||
void execFunction(void (*function)(void *args));
|
||||
|
||||
/**
|
||||
* @brief Use this function when your function is a wuick function before
|
||||
* end_menuFunction()
|
||||
*/
|
||||
void setQuick_menuFunction(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //__MENU_MANAGER_H__
|
||||
159
menu_manager.c
Normal file
159
menu_manager.c
Normal file
@@ -0,0 +1,159 @@
|
||||
// TODO: Add comments
|
||||
#include "menu_manager.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/idf_additions.h"
|
||||
#include "freertos/portmacro.h"
|
||||
#include "freertos/projdefs.h"
|
||||
#include "sdkconfig.h"
|
||||
#include <esp_log.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <freertos/task.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
const static char *TAG = "menu_menager";
|
||||
|
||||
TaskHandle_t tMenuFunction = NULL;
|
||||
QueueHandle_t qCommands = NULL;
|
||||
|
||||
menu_path_t steckPath[CONFIG_MAX_DEPTH_PATH];
|
||||
menu_path_t path;
|
||||
uint8_t depth = 0;
|
||||
Navigate_t inputCommand = NAVIGATE_NOTHING;
|
||||
void (**show)(menu_path_t *current_menu);
|
||||
|
||||
static void NavigationUp(bool loop) {
|
||||
ESP_LOGI(TAG, "Command UP");
|
||||
|
||||
if (path.current_index < path.current_menu->num_options - 1 || loop) {
|
||||
path.current_index++;
|
||||
path.current_index %= path.current_menu->num_options;
|
||||
}
|
||||
}
|
||||
|
||||
static void NavigationDown(bool loop) {
|
||||
ESP_LOGI(TAG, "Command DOWN");
|
||||
|
||||
if (path.current_index > 0 || loop) {
|
||||
path.current_index =
|
||||
(path.current_menu->num_options + path.current_index - 1) %
|
||||
path.current_menu->num_options;
|
||||
}
|
||||
}
|
||||
|
||||
static void ExecFunction() {
|
||||
ESP_LOGI(TAG, "Execute Function: %s",
|
||||
path.current_menu->submenus[path.current_index].label);
|
||||
|
||||
xTaskCreatePinnedToCore(
|
||||
path.current_menu->submenus[path.current_index].function,
|
||||
path.current_menu->submenus[path.current_index].label, 10240, NULL, 10,
|
||||
&tMenuFunction, 1);
|
||||
}
|
||||
|
||||
static void SelectionOption() {
|
||||
ESP_LOGI(TAG, "Open Submenu");
|
||||
|
||||
path.current_menu = &path.current_menu->submenus[path.current_index];
|
||||
path.current_index = 0;
|
||||
depth++;
|
||||
steckPath[depth] = path;
|
||||
}
|
||||
|
||||
static void NavigationBack() {
|
||||
ESP_LOGI(TAG, "Command BACK");
|
||||
|
||||
depth--;
|
||||
path = steckPath[depth];
|
||||
#if !CONFIG_SALVE_INDEX
|
||||
path.current_index = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void menu_init(void *args) {
|
||||
ESP_LOGI(TAG, "Start menu");
|
||||
menu_config_t *params = (menu_config_t *)args;
|
||||
|
||||
qCommands = xQueueCreate(10, sizeof(Navigate_t));
|
||||
|
||||
path.current_index = 0;
|
||||
path.current_menu = ¶ms->root;
|
||||
steckPath[depth] = path;
|
||||
|
||||
show = ¶ms->display;
|
||||
(*show)(&path);
|
||||
|
||||
ESP_LOGI(TAG, "Root Title: %s", path.current_menu->label);
|
||||
|
||||
while (true) {
|
||||
|
||||
xQueueReceive(qCommands, &inputCommand, portMAX_DELAY);
|
||||
|
||||
if (tMenuFunction == NULL) {
|
||||
|
||||
switch (inputCommand) {
|
||||
|
||||
case NAVIGATE_UP:
|
||||
NavigationUp(params->loop);
|
||||
break;
|
||||
|
||||
case NAVIGATE_DOWN:
|
||||
NavigationDown(params->loop);
|
||||
break;
|
||||
|
||||
case NAVIGATE_SELECT:
|
||||
if (path.current_menu->submenus[path.current_index].function) {
|
||||
ExecFunction();
|
||||
} else {
|
||||
SelectionOption();
|
||||
}
|
||||
break;
|
||||
|
||||
case NAVIGATE_BACK:
|
||||
if (depth) {
|
||||
NavigationBack();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGW(TAG, "Undenfined Input");
|
||||
break;
|
||||
}
|
||||
|
||||
(*show)(&path);
|
||||
} else if (inputCommand == NAVIGATE_BACK) {
|
||||
vTaskDelete(tMenuFunction);
|
||||
tMenuFunction = NULL;
|
||||
(*show)(&path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void exitFunction(void) {
|
||||
if (tMenuFunction != NULL) {
|
||||
ESP_LOGI(TAG, "Exit Function");
|
||||
(*show)(&path);
|
||||
tMenuFunction = NULL;
|
||||
vTaskDelete(tMenuFunction);
|
||||
}
|
||||
}
|
||||
|
||||
void execFunction(void (*function)(void *args)) {
|
||||
ESP_LOGI(TAG, "Execute Function");
|
||||
|
||||
xTaskCreatePinnedToCore(function, "Function_by_menu", 10240, NULL, 10,
|
||||
&tMenuFunction, 1);
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
void setQuick_menuFunction(void) { (*show)(&path); }
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user