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