#include "Fonts.hpp" #include "esp_log.h" #include "esp_system.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include #if CONFIG_ESP_LVGL_ADAPTER_ENABLE_FREETYPE #include "esp_lv_adapter.h" #include #endif namespace { static const char* TAG = "Fonts"; static constexpr const char* kFontPath = "/sdcard/fonts/Montserrat-Medium.ttf"; static constexpr const char* kIconFontPath = "/sdcard/fonts/MaterialSymbolsOutlined.ttf"; static constexpr uint16_t kFontSizes[] = {14, 18, 22, 28, 36, 48}; static constexpr size_t kFontCount = sizeof(kFontSizes) / sizeof(kFontSizes[0]); static const lv_font_t* s_fonts[kFontCount] = {nullptr}; static const lv_font_t* s_iconFonts[kFontCount] = {nullptr}; static bool s_initialized = false; static bool s_iconFontAvailable = false; const lv_font_t* fallbackFont(uint8_t sizeIndex) { switch (sizeIndex) { case 0: return &lv_font_montserrat_14; #if LV_FONT_MONTSERRAT_18 case 1: return &lv_font_montserrat_18; #endif #if LV_FONT_MONTSERRAT_22 case 2: return &lv_font_montserrat_22; #endif #if LV_FONT_MONTSERRAT_28 case 3: return &lv_font_montserrat_28; #endif #if LV_FONT_MONTSERRAT_36 case 4: return &lv_font_montserrat_36; #endif #if LV_FONT_MONTSERRAT_48 case 5: return &lv_font_montserrat_48; #endif default: return &lv_font_montserrat_14; } } #if CONFIG_ESP_LVGL_ADAPTER_ENABLE_FREETYPE bool fontFileExists(const char* path) { struct stat st; return stat(path, &st) == 0; } #endif } // namespace void Fonts::init() { #if CONFIG_ESP_LVGL_ADAPTER_ENABLE_FREETYPE ESP_LOGI(TAG, "FreeType enabled"); if (s_initialized) { ESP_LOGI(TAG, "Already initialized"); return; } s_initialized = true; if (!fontFileExists(kFontPath)) { ESP_LOGW(TAG, "Font file not found: %s", kFontPath); return; } ESP_LOGI(TAG, "Font file exists: %s", kFontPath); // Give LVGL task time to start and release mutex ESP_LOGI(TAG, "Waiting for LVGL task..."); vTaskDelay(pdMS_TO_TICKS(500)); // Test if LVGL lock is available ESP_LOGI(TAG, "Testing LVGL lock..."); if (esp_lv_adapter_lock(1000) == ESP_OK) { // 1 second timeout ESP_LOGI(TAG, "Lock acquired OK, releasing..."); esp_lv_adapter_unlock(); } else { ESP_LOGE(TAG, "Could not acquire LVGL lock - something is holding it!"); return; // Don't try to init fonts if lock is stuck } for (size_t i = 0; i < kFontCount; ++i) { ESP_LOGI(TAG, "Loading font size %u...", kFontSizes[i]); esp_lv_adapter_ft_font_config_t cfg = {}; cfg.name = kFontPath; cfg.size = kFontSizes[i]; cfg.style = ESP_LV_ADAPTER_FT_FONT_STYLE_NORMAL; cfg.mem = nullptr; cfg.mem_size = 0; esp_lv_adapter_ft_font_handle_t handle = nullptr; ESP_LOGI(TAG, "Calling esp_lv_adapter_ft_font_init (free heap: %lu)...", (unsigned long)esp_get_free_heap_size()); esp_err_t ret = esp_lv_adapter_ft_font_init(&cfg, &handle); ESP_LOGI(TAG, "esp_lv_adapter_ft_font_init returned %d", ret); if (ret != ESP_OK || handle == nullptr) { ESP_LOGW(TAG, "Failed to load FreeType font size %u (err=%d)", cfg.size, ret); continue; } s_fonts[i] = esp_lv_adapter_ft_font_get(handle); if (!s_fonts[i]) { ESP_LOGW(TAG, "FreeType font handle returned null for size %u", cfg.size); } ESP_LOGI(TAG, "Font size %u loaded successfully", kFontSizes[i]); } ESP_LOGI(TAG, "Text font initialization complete"); // Load icon font if available if (fontFileExists(kIconFontPath)) { ESP_LOGI(TAG, "Icon font file exists: %s", kIconFontPath); for (size_t i = 0; i < kFontCount; ++i) { ESP_LOGI(TAG, "Loading icon font size %u...", kFontSizes[i]); esp_lv_adapter_ft_font_config_t cfg = {}; cfg.name = kIconFontPath; cfg.size = kFontSizes[i]; cfg.style = ESP_LV_ADAPTER_FT_FONT_STYLE_NORMAL; cfg.mem = nullptr; cfg.mem_size = 0; esp_lv_adapter_ft_font_handle_t handle = nullptr; esp_err_t ret = esp_lv_adapter_ft_font_init(&cfg, &handle); if (ret != ESP_OK || handle == nullptr) { ESP_LOGW(TAG, "Failed to load icon font size %u (err=%d)", cfg.size, ret); continue; } s_iconFonts[i] = esp_lv_adapter_ft_font_get(handle); if (s_iconFonts[i]) { s_iconFontAvailable = true; ESP_LOGI(TAG, "Icon font size %u loaded successfully", kFontSizes[i]); } } ESP_LOGI(TAG, "Icon font initialization complete"); } else { ESP_LOGW(TAG, "Icon font file not found: %s", kIconFontPath); } #else ESP_LOGI(TAG, "FreeType disabled, using built-in fonts"); #endif } const lv_font_t* Fonts::bySizeIndex(uint8_t sizeIndex) { #if CONFIG_ESP_LVGL_ADAPTER_ENABLE_FREETYPE if (sizeIndex < kFontCount && s_fonts[sizeIndex]) { return s_fonts[sizeIndex]; } #endif return fallbackFont(sizeIndex); } const lv_font_t* Fonts::iconFont(uint8_t sizeIndex) { #if CONFIG_ESP_LVGL_ADAPTER_ENABLE_FREETYPE if (sizeIndex < kFontCount && s_iconFonts[sizeIndex]) { return s_iconFonts[sizeIndex]; } // Try to return any available icon font size as fallback if (s_iconFontAvailable) { for (size_t i = 0; i < kFontCount; ++i) { if (s_iconFonts[i]) return s_iconFonts[i]; } } #endif // No icon font available - return text font as last resort return fallbackFont(sizeIndex); } bool Fonts::hasIconFont() { #if CONFIG_ESP_LVGL_ADAPTER_ENABLE_FREETYPE return s_iconFontAvailable; #else return false; #endif }