Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 13 additions & 0 deletions firmware_p4/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@ cmake_minimum_required(VERSION 3.16)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

set(EXTRA_COMPONENT_DIRS
# Core
"${CMAKE_SOURCE_DIR}/components/Core/freetype"
# Drivers
"${CMAKE_SOURCE_DIR}/components/Drivers/button"
"${CMAKE_SOURCE_DIR}/components/Drivers/knob"
"${CMAKE_SOURCE_DIR}/components/Drivers/esp_lcd_touch"
# Service
"${CMAKE_SOURCE_DIR}/components/Service/esp_lvgl_adapter"
"${CMAKE_SOURCE_DIR}/components/Service/esp_lv_fs"
"${CMAKE_SOURCE_DIR}/components/Service/esp_lv_decoder"
)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)

project(TentacleOS_P4)
Expand Down
1 change: 1 addition & 0 deletions firmware_p4/components/Applications/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -151,5 +151,6 @@ idf_component_register(SRCS
esp_tinyusb
mbedtls
bt
esp_lvgl_adapter
)
target_link_libraries(${COMPONENT_LIB} -Wl,-zmuldefs)
150 changes: 63 additions & 87 deletions firmware_p4/components/Applications/ui/ui_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,15 @@
#include "lv_port_indev.h"
#include "assets_manager.h"

#define TAG "UI_MANAGER"

#define UI_TASK_STACK_SIZE (4096 * 2)
#define UI_TASK_PRIORITY (tskIDLE_PRIORITY + 2)
#define UI_TASK_CORE 1
// esp_lvgl_adapter - 接管 LVGL 任务管理和线程安全锁
#include "esp_lv_adapter.h"

#define LVGL_TICK_PERIOD_MS 5
#define TAG "UI_MANAGER"

static SemaphoreHandle_t xGuiSemaphore = NULL;
// LVGL worker task 配置(由 esp_lv_adapter_start() 创建,在 kernel.c 的 adapter_cfg 中定义)
// 这里只保留 UI 逻辑相关的参数
static bool is_emergency_restart = false;

static void ui_task(void *pvParameter);
static void lv_tick_task(void *arg);
static void clear_current_screen(void);

static bool is_ble_screen(screen_id_t screen) {
Expand All @@ -85,89 +81,78 @@ static bool is_badusb_screen(screen_id_t screen) {

screen_id_t current_screen_id = SCREEN_NONE;

// ---------------------------------------------------------------------------
// Boot sequence task(在 LVGL worker task 之外单独执行)
// ---------------------------------------------------------------------------
static void ui_boot_task(void *pvParameter)
{
ui_theme_init();

bool is_recovery = is_emergency_restart;
is_emergency_restart = false;

if (ui_acquire()) {
if (is_recovery) {
ui_home_open();
msgbox_open(LV_SYMBOL_WARNING, "UI Recovered!\nInterface task was restarted.", "OK", NULL, NULL);
} else {
ui_boot_show();
}
ui_release();
}

// 等待 5 秒后切换到主页
vTaskDelay(pdMS_TO_TICKS(5000));

if (ui_acquire()) {
if (!is_recovery) {
ui_home_open();
}
ui_release();
}

vTaskDelete(NULL);
}

void ui_init(void)
{
ESP_LOGI(TAG, "Initializing UI Manager...");

assets_manager_init();

ui_theme_init();

xGuiSemaphore = xSemaphoreCreateRecursiveMutex();
if (!xGuiSemaphore) {
ESP_LOGE(TAG, "Failed to create UI Mutex");
return;
}

const esp_timer_create_args_t periodic_timer_args = {
.callback = &lv_tick_task,
.name = "lvgl_tick"
};
esp_timer_handle_t periodic_timer;
ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, LVGL_TICK_PERIOD_MS * 1000));
// 启动 esp_lvgl_adapter 的 LVGL worker task(替代原来手动创建的 ui_task + lv_tick_task)
// adapter 自己管理 lv_timer_handler() 的调用和 tick 计时
ESP_ERROR_CHECK(esp_lv_adapter_start());

// 在单独的任务中处理启动画面(否则会阻塞 init 流程)
xTaskCreatePinnedToCore(
ui_task,
"UI Task",
UI_TASK_STACK_SIZE,
NULL,
UI_TASK_PRIORITY,
NULL,
UI_TASK_CORE
ui_boot_task,
"UI Boot",
4096 * 2,
NULL,
tskIDLE_PRIORITY + 2,
NULL,
1
);

ESP_LOGI(TAG, "UI Manager initialized successfully.");
}

void ui_hard_restart(void) {
ESP_LOGW(TAG, "Executing UI Task Emergency Restart...");
ESP_LOGW(TAG, "Executing UI Emergency Restart...");
is_emergency_restart = true;
xTaskCreatePinnedToCore(
ui_task,
"UI Task",
UI_TASK_STACK_SIZE,
NULL,
UI_TASK_PRIORITY,
NULL,
UI_TASK_CORE
ui_boot_task,
"UI Boot",
4096 * 2,
NULL,
tskIDLE_PRIORITY + 2,
NULL,
1
);
}

static void ui_task(void *pvParameter)
{
ui_theme_init();

bool is_recovery = is_emergency_restart;
is_emergency_restart = false;

if (ui_acquire()) {
if (is_recovery) {
ui_home_open();
msgbox_open(LV_SYMBOL_WARNING, "UI Recovered!\nInterface task was restarted.", "OK", NULL, NULL);
} else {
ui_boot_show();
}
ui_release();
}

TickType_t start_tick = xTaskGetTickCount();
bool boot_screen_done = is_recovery;

while (1) {
if (ui_acquire()) {
if (!boot_screen_done && (xTaskGetTickCount() - start_tick >= pdMS_TO_TICKS(5000))) {
ui_home_open();
boot_screen_done = true;
}

lv_timer_handler();
ui_release();
}
vTaskDelay(pdMS_TO_TICKS(10));
}
}

static void clear_current_screen(void){
lv_group_remove_all_objs(main_group);
}
Expand Down Expand Up @@ -366,26 +351,17 @@ void ui_switch_screen(screen_id_t new_screen) {
}
}

static void lv_tick_task(void *arg)
{
(void) arg;
lv_tick_inc(LVGL_TICK_PERIOD_MS);
}

// ---------------------------------------------------------------------------
// 线程安全 API(委托给 esp_lv_adapter 的递归互斥锁)
// ---------------------------------------------------------------------------

bool ui_acquire(void)
{
if (xGuiSemaphore != NULL) {
return (xSemaphoreTakeRecursive(xGuiSemaphore, portMAX_DELAY) == pdTRUE);
}
return false;
// esp_lv_adapter_lock(-1) 表示无限等待,与原 portMAX_DELAY 行为一致
return (esp_lv_adapter_lock(-1) == ESP_OK);
}

void ui_release(void)
{
if (xGuiSemaphore != NULL) {
xSemaphoreGiveRecursive(xGuiSemaphore);
}
esp_lv_adapter_unlock();
}


20 changes: 20 additions & 0 deletions firmware_p4/components/Core/freetype/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
idf_component_register()

# Override options defined in freetype/CMakeLists.txt.
# We could have used normal set(...) here if freetype enabled CMake policy CMP0077.
option(FT_DISABLE_HARFBUZZ "" ON)
option(FT_DISABLE_BZIP2 "" ON)
option(FT_DISABLE_BROTLI "" ON)
option(FT_DISABLE_PNG "" ON)
option(FT_DISABLE_ZLIB "" ON)

# These are regular CMake variables, so we can set them directly.
set(SKIP_INSTALL_ALL TRUE)
set(BUILD_SHARED_LIBS OFF)

add_subdirectory(freetype output)

# https://gitlab.freedesktop.org/freetype/freetype/-/issues/1299
target_compile_options(freetype PRIVATE "-Wno-dangling-pointer")

target_link_libraries(${COMPONENT_LIB} INTERFACE freetype)
46 changes: 46 additions & 0 deletions firmware_p4/components/Core/freetype/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
FREETYPE LICENSES
-----------------

The FreeType 2 font engine is copyrighted work and cannot be used
legally without a software license. In order to make this project
usable to a vast majority of developers, we distribute it under two
mutually exclusive open-source licenses.

This means that *you* must choose *one* of the two licenses described
below, then obey all its terms and conditions when using FreeType 2 in
any of your projects or products.

- The FreeType License, found in the file `docs/FTL.TXT`, which is
similar to the original BSD license *with* an advertising clause
that forces you to explicitly cite the FreeType project in your
product's documentation. All details are in the license file.
This license is suited to products which don't use the GNU General
Public License.

Note that this license is compatible to the GNU General Public
License version 3, but not version 2.

- The GNU General Public License version 2, found in
`docs/GPLv2.TXT` (any later version can be used also), for
programs which already use the GPL. Note that the FTL is
incompatible with GPLv2 due to its advertisement clause.

The contributed BDF and PCF drivers come with a license similar to
that of the X Window System. It is compatible to the above two
licenses (see files `src/bdf/README` and `src/pcf/README`). The same
holds for the source code files `src/base/fthash.c` and
`include/freetype/internal/fthash.h`; they were part of the BDF driver
in earlier FreeType versions.

The gzip module uses the zlib license (see `src/gzip/zlib.h`) which
too is compatible to the above two licenses.

The files `src/autofit/ft-hb.c` and `src/autofit/ft-hb.h` contain code
taken almost verbatim from the HarfBuzz file `hb-ft.cc`, which uses
the 'Old MIT' license, compatible to the above two licenses.

The MD5 checksum support (only used for debugging in development
builds) is in the public domain.


--- end of LICENSE.TXT ---
7 changes: 7 additions & 0 deletions firmware_p4/components/Core/freetype/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# freetype compression and decompression Library

[![Component Registry](https://components.espressif.com/components/espressif/freetype/badge.svg)](https://components.espressif.com/components/espressif/freetype)

This is an IDF component for freetype library.

For usage instructions, please refer to the official documentation: https://freetype.org/freetype2/docs/documentation.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.17)

set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(freetype-example)
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# FreeType Example

This is a simple example of initializing FreeType library, loading a font from a filesystem, and rendering a line of text.

The font file (DejaVu Sans) is downloaded at compile time and is added into a SPIFFS filesystem image. The filesystem is flashed to the board together with the application. The example loads the font file and renders "FreeType" text into the console as ASCII art.

This example doesn't require any special hardware and can run on any development board.

## Building and running

Run the application as usual for an ESP-IDF project. For example, for ESP32:
```
idf.py set-target esp32
idf.py -p PORT flash monitor
```

## Example output

The example should output the following:

```
I (468) main_task: Calling app_main()
I (538) example: FreeType library initialized
I (1258) example: Font loaded
I (1268) example: Rendering char: 'F'
I (1388) example: Rendering char: 'r'
I (1528) example: Rendering char: 'e'
I (1658) example: Rendering char: 'e'
I (1798) example: Rendering char: 'T'
I (1938) example: Rendering char: 'y'
I (2078) example: Rendering char: 'p'
I (2208) example: Rendering char: 'e'


######. #########
## +#
## ##### +###+ +###+ +# +# ######## +###+
## ##+ +#. .#+ +#. .#+ +# #+ #+##+ .#+ +#. .#+
###### ## #+ +# #+ +# +# ## +# ## +# #+ +#
## ## .####### .####### +# .# ## ## .# .#######
## ## .#. .#. +# #+.#. ## .# .#.
## ## #+ #+ +# +### ## +# #+
## ## ##+ ++ ##+ ++ +# ##+ ##+ .#+ ##+ ++
## ## +#### +#### +# ## ###### +####
## ##
+#. ##
##+ ##



```
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
idf_component_register(SRCS "freetype-example.c"
INCLUDE_DIRS "."
PRIV_REQUIRES spiffs)

# Download the example font into a directory "spiffs" in the build directory
set(URL "https://github.com/espressif/esp-docs/raw/f036a337d8bee5d1a93b2264ecd29255baec4260/src/esp_docs/fonts/DejaVuSans.ttf")
set(FILE "DejaVuSans.ttf")
set(SPIFFS_DIR "${CMAKE_BINARY_DIR}/spiffs")
file(MAKE_DIRECTORY ${SPIFFS_DIR})
file(DOWNLOAD ${URL} ${SPIFFS_DIR}/${FILE} SHOW_PROGRESS)

# Create a partition named "fonts" with the example font
spiffs_create_partition_image(fonts ${SPIFFS_DIR} FLASH_IN_PROJECT)
Loading
Loading