From f4088f57629ff6f8b7fc0cea6ac23569b932899a Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Wed, 27 Dec 2023 13:57:20 +0100 Subject: [PATCH] various improvements stopped using private header folder (for ease of development - for now) implemented basic gui service (WIP) added sdkconfig.defaults to the repo updated docs --- .gitignore | 2 +- README.md | 11 ++- .../board_2432s024/board_2432s024_display.c | 60 ++++++------ components/furi/src/m_cstr_dup.h | 1 - components/nanobake/CMakeLists.txt | 5 +- .../src/applications/services/gui/gui.c | 93 ++++++++++++++++++- .../src/applications/services/gui/gui.h | 13 +++ .../system_info/system_info.c | 0 .../system_info/system_info.h | 0 components/nanobake/src/nanobake.c | 2 +- components/nanobake/{inc => src}/nanobake.h | 2 +- components/nanobake/{inc => src}/nb_app.h | 0 components/nanobake/{inc => src}/nb_config.h | 0 components/nanobake/src/nb_display.c | 7 ++ components/nanobake/{inc => src}/nb_display.h | 1 + .../nanobake/{inc => src}/nb_hardware.h | 0 components/nanobake/src/nb_lvgl.c | 2 +- components/nanobake/{inc => src}/nb_lvgl.h | 0 components/nanobake/{inc => src}/nb_touch.h | 0 main/src/hello_world/hello_world.c | 47 +++++++--- main/src/main.c | 2 +- sdkconfig.defaults | 4 + 22 files changed, 202 insertions(+), 50 deletions(-) rename components/nanobake/src/applications/{main => system}/system_info/system_info.c (100%) rename components/nanobake/src/applications/{main => system}/system_info/system_info.h (100%) rename components/nanobake/{inc => src}/nanobake.h (80%) rename components/nanobake/{inc => src}/nb_app.h (100%) rename components/nanobake/{inc => src}/nb_config.h (100%) rename components/nanobake/{inc => src}/nb_display.h (97%) rename components/nanobake/{inc => src}/nb_hardware.h (100%) rename components/nanobake/{inc => src}/nb_lvgl.h (100%) rename components/nanobake/{inc => src}/nb_touch.h (100%) create mode 100644 sdkconfig.defaults diff --git a/.gitignore b/.gitignore index 931d5efe..806e4d66 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,7 @@ CMakeCache.txt *.cbp sdkconfig -sdkconfig.* +sdkconfig.old managed_components/ dependencies.lock diff --git a/README.md b/README.md index 6521cbc2..a8fb840b 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,11 @@ Nanobake provides: - UI capabilities (via LVGL) - An application platform that can run apps and services +Requirements: +- ESP32 (any?) +- [esp-idf 5.1.x](https://docs.espressif.com/projects/esp-idf/en/v5.1.2/esp32/get-started/index.html) +- a display (connected via SPI or I2C) + **Status: pre-alpha** ## Technologies @@ -20,10 +25,10 @@ UI is created with [lvgl](https://github.com/lvgl/lvgl) via [esp_lvgl_port](http ### Devices -In theory, all hardware from the [Board Support Packages](https://github.com/espressif/esp-bsp/) project is supported. - -In practice, there are pre-configured drivers available for these boards: +See below for the supported hardware. +Predefined configurations are available for: - Yellow Board / 2432S024 +- (more will follow) ### Drivers diff --git a/components/board_2432s024/board_2432s024_display.c b/components/board_2432s024/board_2432s024_display.c index e67a91fd..218dda3e 100644 --- a/components/board_2432s024/board_2432s024_display.c +++ b/components/board_2432s024/board_2432s024_display.c @@ -14,17 +14,17 @@ static const char* TAG = "2432s024_ili9341"; static SemaphoreHandle_t refresh_finish = NULL; -#define SELECTED_SPI_HOST SPI2_HOST -#define PIN_SCLK GPIO_NUM_14 -#define PIN_MOSI GPIO_NUM_13 -#define PIN_CS GPIO_NUM_15 -#define PIN_DC GPIO_NUM_2 -#define PIN_BACKLIGHT GPIO_NUM_27 +#define LCD_SPI_HOST SPI2_HOST +#define LCD_PIN_SCLK GPIO_NUM_14 +#define LCD_PIN_MOSI GPIO_NUM_13 +#define LCD_PIN_CS GPIO_NUM_15 +#define LCD_PIN_DC GPIO_NUM_2 +#define LCD_PIN_BACKLIGHT GPIO_NUM_27 -#define HORIZONTAL_RESOLUTION 240 -#define VERTICAL_RESOLUTION 320 -#define BITS_PER_PIXEL 16 -#define DRAW_BUFFER_HEIGHT 80 +#define LCD_HORIZONTAL_RESOLUTION 240 +#define LCD_VERTICAL_RESOLUTION 320 +#define LCD_BITS_PER_PIXEL 16 +#define LCD_DRAW_BUFFER_HEIGHT 80 IRAM_ATTR static bool prv_on_color_trans_done(esp_lcd_panel_io_handle_t io_handle, esp_lcd_panel_io_event_data_t* edata, void* user_ctx) { BaseType_t need_yield = pdFALSE; @@ -36,7 +36,7 @@ static bool prv_create_display(nb_display_t* display) { ESP_LOGI(TAG, "creating display"); gpio_config_t io_conf = { - .pin_bit_mask = BIT64(PIN_BACKLIGHT), + .pin_bit_mask = BIT64(LCD_PIN_BACKLIGHT), .mode = GPIO_MODE_OUTPUT, .pull_up_en = GPIO_PULLUP_DISABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, @@ -44,25 +44,26 @@ static bool prv_create_display(nb_display_t* display) { }; gpio_config(&io_conf); + size_t draw_buffer_size = LCD_HORIZONTAL_RESOLUTION * LCD_DRAW_BUFFER_HEIGHT * (LCD_BITS_PER_PIXEL / 8); const spi_bus_config_t bus_config = ILI9341_PANEL_BUS_SPI_CONFIG( - PIN_SCLK, - PIN_MOSI, - HORIZONTAL_RESOLUTION * DRAW_BUFFER_HEIGHT * (BITS_PER_PIXEL / 8) + LCD_PIN_SCLK, + LCD_PIN_MOSI, + draw_buffer_size ); - if (spi_bus_initialize(SELECTED_SPI_HOST, &bus_config, SPI_DMA_CH_AUTO) != ESP_OK) { + if (spi_bus_initialize(LCD_SPI_HOST, &bus_config, SPI_DMA_CH_AUTO) != ESP_OK) { ESP_LOGD(TAG, "spi bus init failed"); return false; } const esp_lcd_panel_io_spi_config_t panel_io_config = ILI9341_PANEL_IO_SPI_CONFIG( - PIN_CS, - PIN_DC, + LCD_PIN_CS, + LCD_PIN_DC, prv_on_color_trans_done, NULL ); - if (esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)SELECTED_SPI_HOST, &panel_io_config, &display->io_handle) != ESP_OK) { + if (esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_SPI_HOST, &panel_io_config, &display->io_handle) != ESP_OK) { ESP_LOGD(TAG, "failed to create panel"); return false; } @@ -71,8 +72,9 @@ static bool prv_create_display(nb_display_t* display) { const esp_lcd_panel_dev_config_t panel_config = { .reset_gpio_num = GPIO_NUM_NC, .rgb_endian = LCD_RGB_ENDIAN_RGB, - .bits_per_pixel = BITS_PER_PIXEL, + .bits_per_pixel = LCD_BITS_PER_PIXEL, }; + if (esp_lcd_new_panel_ili9341(display->io_handle, &panel_config, &display->display_handle) != ESP_OK) { ESP_LOGD(TAG, "failed to create ili9341"); return false; @@ -91,6 +93,14 @@ static bool prv_create_display(nb_display_t* display) { if (esp_lcd_panel_mirror(display->display_handle, true, false) != ESP_OK) { ESP_LOGD(TAG, "failed to set panel to mirror"); + display->mirror_x = true; + display->mirror_y = false; + return false; + } + + if (esp_lcd_panel_swap_xy(display->display_handle, false) != ESP_OK) { + ESP_LOGD(TAG, "failed to set panel xy swap"); + display->swap_xy = false; return false; } @@ -99,17 +109,15 @@ static bool prv_create_display(nb_display_t* display) { return false; } - if (gpio_set_level(PIN_BACKLIGHT, 1) != ESP_OK) { + if (gpio_set_level(LCD_PIN_BACKLIGHT, 1) != ESP_OK) { ESP_LOGD(TAG, "failed to turn backlight on"); return false; } - display->horizontal_resolution = HORIZONTAL_RESOLUTION; - display->vertical_resolution = VERTICAL_RESOLUTION; - display->draw_buffer_height = DRAW_BUFFER_HEIGHT; - display->bits_per_pixel = BITS_PER_PIXEL; - display->mirror_x = true; - display->mirror_y = false; + display->horizontal_resolution = LCD_HORIZONTAL_RESOLUTION; + display->vertical_resolution = LCD_VERTICAL_RESOLUTION; + display->draw_buffer_height = LCD_DRAW_BUFFER_HEIGHT; + display->bits_per_pixel = LCD_BITS_PER_PIXEL; return true; } diff --git a/components/furi/src/m_cstr_dup.h b/components/furi/src/m_cstr_dup.h index 40a6dbc5..92908fef 100644 --- a/components/furi/src/m_cstr_dup.h +++ b/components/furi/src/m_cstr_dup.h @@ -1,4 +1,3 @@ -// File originated from Flipper Zero / Furi #pragma once #include diff --git a/components/nanobake/CMakeLists.txt b/components/nanobake/CMakeLists.txt index 5f9f0a03..48680997 100644 --- a/components/nanobake/CMakeLists.txt +++ b/components/nanobake/CMakeLists.txt @@ -1,11 +1,10 @@ idf_component_register( SRC_DIRS "src" "src/applications" - "src/applications/main/system_info" + "src/applications/system/system_info" "src/applications/services/desktop" "src/applications/services/loader" "src/applications/services/gui" - INCLUDE_DIRS "inc" - PRIV_INCLUDE_DIRS "src" + INCLUDE_DIRS "src" REQUIRES esp_lvgl_port esp_lcd esp_lcd_touch driver mlib cmsis_core furi ) diff --git a/components/nanobake/src/applications/services/gui/gui.c b/components/nanobake/src/applications/services/gui/gui.c index 77589dd0..f927d593 100644 --- a/components/nanobake/src/applications/services/gui/gui.c +++ b/components/nanobake/src/applications/services/gui/gui.c @@ -1,9 +1,100 @@ #include "gui.h" #include "core_defines.h" -#include "check.h" +#include +#include +#include +#include +#include + +typedef struct screen screen_t; +struct screen { + screen_id_t id; + lv_obj_t* parent; + on_init_lvgl _Nonnull callback; +}; + +static screen_id_t screen_counter = 0; + +DICT_DEF2(screen_dict, screen_id_t, M_BASIC_OPLIST, screen_t, M_POD_OPLIST) + +typedef struct Gui Gui; +struct Gui { + // TODO: use mutex + FuriMutex* mutex; + screen_dict_t screens; +}; + +Gui* gui_alloc() { + Gui* gui = malloc(sizeof(Gui)); + screen_dict_init(gui->screens); + gui->mutex = furi_mutex_alloc(FuriMutexTypeNormal); + return gui; +} + +void gui_free(Gui* gui) { + screen_dict_clear(gui->screens); + furi_mutex_free(gui->mutex); + free(gui); +} + +void gui_lock(Gui* gui) { + furi_assert(gui); + furi_check(furi_mutex_acquire(gui->mutex, FuriWaitForever) == FuriStatusOk); +} + +void gui_unlock(Gui* gui) { + furi_assert(gui); + furi_check(furi_mutex_release(gui->mutex) == FuriStatusOk); +} + +screen_id_t gui_screen_create(Gui* gui, on_init_lvgl callback) { + screen_id_t id = screen_counter++; + screen_t screen = { + .id = id, + .parent = NULL, + .callback = callback + }; + + screen_dict_set_at(gui->screens, id, screen); + + // TODO: notify desktop of change + // TODO: have desktop update views + lv_obj_t* parent = lv_scr_act(); + gui_screen_set_parent(gui, id, parent); + + // TODO: call from desktop + screen.callback(gui_screen_get_parent(gui, id), id); + + return id; +} + +lv_obj_t* gui_screen_get_parent(Gui* gui, screen_id_t id) { + screen_t* screen = screen_dict_get(gui->screens, id); + furi_check(screen != NULL); + return screen->parent; +} + +void gui_screen_set_parent(Gui* gui, screen_id_t id, lv_obj_t* parent) { + screen_t* screen = screen_dict_get(gui->screens, id); + furi_check(screen != NULL); + screen->parent = parent; +} + +void gui_screen_free(Gui* gui, screen_id_t id) { + screen_t* screen = screen_dict_get(gui->screens, id); + furi_check(screen != NULL); + + // TODO: notify? use callback? (done from desktop service) + lv_obj_clean(screen->parent); + + screen_dict_erase(gui->screens, id); +} static int32_t prv_gui_main(void* param) { UNUSED(param); + + Gui* gui = gui_alloc(); + furi_record_create(RECORD_GUI, gui); printf("gui app init\n"); return 0; } diff --git a/components/nanobake/src/applications/services/gui/gui.h b/components/nanobake/src/applications/services/gui/gui.h index 07090ef4..ad919ded 100644 --- a/components/nanobake/src/applications/services/gui/gui.h +++ b/components/nanobake/src/applications/services/gui/gui.h @@ -6,6 +6,19 @@ extern "C" { #endif +#define RECORD_GUI "gui" + +typedef uint16_t screen_id_t; + +typedef struct Gui Gui; +typedef void (*on_init_lvgl)(lv_obj_t*, screen_id_t); + +screen_id_t gui_screen_create(Gui* gui, on_init_lvgl callback); +void gui_screen_free(Gui* gui, screen_id_t id); +// TODO make internal +void gui_screen_set_parent(Gui* gui, screen_id_t id, lv_obj_t* parent); +lv_obj_t* gui_screen_get_parent(Gui* gui, screen_id_t id); + extern const nb_app_t gui_app; #ifdef __cplusplus diff --git a/components/nanobake/src/applications/main/system_info/system_info.c b/components/nanobake/src/applications/system/system_info/system_info.c similarity index 100% rename from components/nanobake/src/applications/main/system_info/system_info.c rename to components/nanobake/src/applications/system/system_info/system_info.c diff --git a/components/nanobake/src/applications/main/system_info/system_info.h b/components/nanobake/src/applications/system/system_info/system_info.h similarity index 100% rename from components/nanobake/src/applications/main/system_info/system_info.h rename to components/nanobake/src/applications/system/system_info/system_info.h diff --git a/components/nanobake/src/nanobake.c b/components/nanobake/src/nanobake.c index e6fb7018..625ae4ee 100644 --- a/components/nanobake/src/nanobake.c +++ b/components/nanobake/src/nanobake.c @@ -58,7 +58,7 @@ static void prv_start_app(const nb_app_t _Nonnull* app) { thread_ids_push_back(prv_thread_ids, thread_id); } -extern void nanobake_start(nb_config_t _Nonnull* config) { +__attribute__((unused)) extern void nanobake_start(nb_config_t _Nonnull* config) { prv_furi_init(); nb_hardware_t hardware = nb_hardware_create(config); diff --git a/components/nanobake/inc/nanobake.h b/components/nanobake/src/nanobake.h similarity index 80% rename from components/nanobake/inc/nanobake.h rename to components/nanobake/src/nanobake.h index 691acefb..9759cc03 100644 --- a/components/nanobake/inc/nanobake.h +++ b/components/nanobake/src/nanobake.h @@ -12,7 +12,7 @@ extern "C" { typedef void* FuriThreadId; typedef struct nb_lvgl nb_lvgl_t; -extern void nanobake_start(nb_config_t _Nonnull * config); +__attribute__((unused)) extern void nanobake_start(nb_config_t _Nonnull * config); extern FuriThreadId nanobake_get_app_thread_id(size_t index); extern size_t nanobake_get_app_thread_count(); diff --git a/components/nanobake/inc/nb_app.h b/components/nanobake/src/nb_app.h similarity index 100% rename from components/nanobake/inc/nb_app.h rename to components/nanobake/src/nb_app.h diff --git a/components/nanobake/inc/nb_config.h b/components/nanobake/src/nb_config.h similarity index 100% rename from components/nanobake/inc/nb_config.h rename to components/nanobake/src/nb_config.h diff --git a/components/nanobake/src/nb_display.c b/components/nanobake/src/nb_display.c index 4e8d9d8d..0ec250c8 100644 --- a/components/nanobake/src/nb_display.c +++ b/components/nanobake/src/nb_display.c @@ -3,6 +3,13 @@ nb_display_t _Nonnull* nb_display_alloc(nb_display_driver_t _Nonnull* driver) { nb_display_t _Nonnull* display = malloc(sizeof(nb_display_t)); + memset(display, 0, sizeof(nb_display_t)); furi_check(driver->create_display(display), "failed to create display"); + furi_check(display->io_handle != NULL); + furi_check(display->display_handle != NULL); + furi_check(display->horizontal_resolution != 0); + furi_check(display->vertical_resolution != 0); + furi_check(display->draw_buffer_height > 0); + furi_check(display->bits_per_pixel > 0); return display; } diff --git a/components/nanobake/inc/nb_display.h b/components/nanobake/src/nb_display.h similarity index 97% rename from components/nanobake/inc/nb_display.h rename to components/nanobake/src/nb_display.h index cfa00059..58581d91 100644 --- a/components/nanobake/inc/nb_display.h +++ b/components/nanobake/src/nb_display.h @@ -17,6 +17,7 @@ struct nb_display { esp_lcd_panel_handle_t _Nonnull display_handle; bool mirror_x; bool mirror_y; + bool swap_xy; }; typedef struct nb_display_driver nb_display_driver_t; diff --git a/components/nanobake/inc/nb_hardware.h b/components/nanobake/src/nb_hardware.h similarity index 100% rename from components/nanobake/inc/nb_hardware.h rename to components/nanobake/src/nb_hardware.h diff --git a/components/nanobake/src/nb_lvgl.c b/components/nanobake/src/nb_lvgl.c index 83b955d8..63d469b7 100644 --- a/components/nanobake/src/nb_lvgl.c +++ b/components/nanobake/src/nb_lvgl.c @@ -28,7 +28,7 @@ nb_lvgl_t nb_lvgl_init(nb_hardware_t _Nonnull* hardware) { .vres = display->vertical_resolution, .monochrome = false, .rotation = { - .swap_xy = false, + .swap_xy = display->swap_xy, .mirror_x = display->mirror_x, .mirror_y = display->mirror_y, }, diff --git a/components/nanobake/inc/nb_lvgl.h b/components/nanobake/src/nb_lvgl.h similarity index 100% rename from components/nanobake/inc/nb_lvgl.h rename to components/nanobake/src/nb_lvgl.h diff --git a/components/nanobake/inc/nb_touch.h b/components/nanobake/src/nb_touch.h similarity index 100% rename from components/nanobake/inc/nb_touch.h rename to components/nanobake/src/nb_touch.h diff --git a/main/src/hello_world/hello_world.c b/main/src/hello_world/hello_world.c index 9434323e..bc66706f 100644 --- a/main/src/hello_world/hello_world.c +++ b/main/src/hello_world/hello_world.c @@ -1,37 +1,62 @@ #include "hello_world.h" #include - +#include #include +#include +#include #include #include -#include static const char* TAG = "app_helloworld"; static void prv_on_button_click(lv_event_t _Nonnull* event) { ESP_LOGI(TAG, "button clicked"); + // Open Gui record + Gui* gui = furi_record_open(RECORD_GUI); + + // Free this screen + screen_id_t screen_id = (screen_id_t)event->user_data; + gui_screen_free(gui, screen_id); + + // Close Gui record + furi_record_close(RECORD_GUI); + gui = NULL; } -static int32_t prv_on_create(void* param) { - UNUSED(param); +static void prv_hello_world_lvgl(lv_obj_t* parent, screen_id_t screen_id) { lvgl_port_lock(0); - lv_obj_t* lv_parent = lv_scr_act(); - - lv_obj_t* label = lv_label_create(lv_parent); + lv_obj_t* label = lv_label_create(parent); lv_label_set_recolor(label, true); lv_obj_set_width(label, 200); lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0); lv_label_set_text(label, "Hello, world!"); lv_obj_align(label, LV_ALIGN_CENTER, 0, -30); - lv_obj_t* btn = lv_btn_create(lv_parent); + lv_obj_t* btn = lv_btn_create(parent); label = lv_label_create(btn); - lv_label_set_text_static(label, "Button"); + lv_label_set_text_static(label, "Exit"); lv_obj_align(btn, LV_ALIGN_CENTER, 0, 30); - lv_obj_add_event_cb(btn, prv_on_button_click, LV_EVENT_CLICKED, NULL); + lv_obj_add_event_cb(btn, prv_on_button_click, LV_EVENT_CLICKED, (void*)screen_id); lvgl_port_unlock(); + + // TODO: on app exit, call gui_screen_destroy() +} + +static int32_t prv_hello_world_main(void* param) { + UNUSED(param); + + // Open Gui record + Gui* gui = furi_record_open(RECORD_GUI); + + // Register an lvgl screen + gui_screen_create(gui, &prv_hello_world_lvgl); + + // Close Gui record + furi_record_close(RECORD_GUI); + gui = NULL; + return 0; } @@ -39,7 +64,7 @@ const nb_app_t hello_world_app = { .id = "helloworld", .name = "Hello World", .type = USER, - .entry_point = &prv_on_create, + .entry_point = &prv_hello_world_main, .stack_size = 2048, .priority = 10 }; diff --git a/main/src/main.c b/main/src/main.c index 29484c98..f2b0c3e4 100644 --- a/main/src/main.c +++ b/main/src/main.c @@ -7,7 +7,7 @@ // Apps #include "hello_world/hello_world.h" -void app_main(void) { +__attribute__((unused)) void app_main(void) { static nb_config_t config = { .display_driver = &board_2432s024_create_display_driver, .touch_driver = &board_2432s024_create_touch_driver, diff --git a/sdkconfig.defaults b/sdkconfig.defaults new file mode 100644 index 00000000..52fe03ad --- /dev/null +++ b/sdkconfig.defaults @@ -0,0 +1,4 @@ +CONFIG_IDF_TARGET="esp32" +CONFIG_LV_COLOR_16_SWAP=y +CONFIG_LV_USE_USER_DATA=y +