#include #include "meteofrance.h" #include "eventsManager.h" #include "esp_lcd_panel_ops.h" #include "esp_lcd_qemu_rgb.h" #include "lvgl.h" #include "esp_log.h" #include "ihm.h" #include "esp_heap_caps.h" extern EventGroupHandle_t domotic_event_group; /** * 32-bit and 16-bit colors are currently supported by QEMU RGB Panel */ #if CONFIG_LV_COLOR_DEPTH_32 #define CURRENT_COLOR_DEPTH RGB_QEMU_BPP_32 #elif CONFIG_LV_COLOR_DEPTH_16 #define CURRENT_COLOR_DEPTH RGB_QEMU_BPP_16 #else #error "QEMU RGB Panel only supports 32-bit and 16-bit colors, please enable LV_COLOR_DEPTH_32 or LV_COLOR_DEPTH_16" #endif // The pixel number in horizontal and vertical #define EXAMPLE_LCD_H_RES 800 #define EXAMPLE_LCD_V_RES 480 #define EXAMPLE_LVGL_TICK_PERIOD_MS 2 #define EXAMPLE_LVGL_TASK_MAX_DELAY_MS 500 #define EXAMPLE_LVGL_TASK_MIN_DELAY_MS 1 #define EXAMPLE_LVGL_TASK_STACK_SIZE (10 * 1024) #define EXAMPLE_LVGL_TASK_PRIORITY 2 static const char *TAG = "example"; SemaphoreHandle_t lvgl_mux; static void example_lvgl_flush_cb(lv_display_t *drv, const lv_area_t *area, unsigned char * color_map) { esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t)drv->user_data; int offsetx1 = area->x1; int offsetx2 = area->x2; int offsety1 = area->y1; int offsety2 = area->y2; // pass the draw buffer to the driver esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map); lv_disp_flush_ready(drv); } static void example_increase_lvgl_tick(void *arg) { /* Tell LVGL how many milliseconds has elapsed */ lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS); } bool example_lvgl_lock(int timeout_ms) { // Convert timeout in milliseconds to FreeRTOS ticks // If `timeout_ms` is set to -1, the program will block until the condition is met const TickType_t timeout_ticks = (timeout_ms == -1) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms); return xSemaphoreTakeRecursive(lvgl_mux, timeout_ticks) == pdTRUE; } void example_lvgl_unlock(void) { xSemaphoreGiveRecursive(lvgl_mux); } static void example_lvgl_port_task(void *arg) { ESP_LOGI(TAG, "Starting LVGL task"); uint32_t task_delay_ms = EXAMPLE_LVGL_TASK_MAX_DELAY_MS; while (1) { // Lock the mutex due to the LVGL APIs are not thread-safe if (example_lvgl_lock(-1)) { task_delay_ms = lv_timer_handler(); // Release the mutex example_lvgl_unlock(); } if (task_delay_ms > EXAMPLE_LVGL_TASK_MAX_DELAY_MS) { task_delay_ms = EXAMPLE_LVGL_TASK_MAX_DELAY_MS; } else if (task_delay_ms < EXAMPLE_LVGL_TASK_MIN_DELAY_MS) { task_delay_ms = EXAMPLE_LVGL_TASK_MIN_DELAY_MS; } vTaskDelay(pdMS_TO_TICKS(task_delay_ms)); } } static size_t example_lvgl_get_buffers(esp_lcd_panel_handle_t panel_handle, void **buf1, void **buf2) { if (buf2) { *buf2 = NULL; } #if CONFIG_EXAMPLE_QEMU_RGB_PANEL_DEDIC_FB ESP_LOGI(TAG, "Use QEMU dedicated frame buffer as LVGL draw buffer"); ESP_ERROR_CHECK(esp_lcd_rgb_qemu_get_frame_buffer(panel_handle, buf1)); return EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES; #else ESP_LOGI(TAG, "Allocate separate LVGL draw buffer"); /* Allocate 10 horizontal lines as the frame buffer */ *buf1 = malloc(EXAMPLE_LCD_H_RES * 10 * sizeof(lv_color_t)); assert(*buf1); return EXAMPLE_LCD_H_RES * 10; #endif // CONFIG_EXAMPLE_DOUBLE_FB } void app_main() { printf(">>> app_main() from test_main.c under Linux\n"); startEvtManager(); ESP_LOGI(TAG, "Install RGB LCD panel driver"); esp_lcd_panel_handle_t panel_handle = NULL; esp_lcd_rgb_qemu_config_t panel_config = { .width = EXAMPLE_LCD_H_RES, .height = EXAMPLE_LCD_V_RES, .bpp = CURRENT_COLOR_DEPTH, }; ESP_ERROR_CHECK(esp_lcd_new_rgb_qemu(&panel_config, &panel_handle)); ESP_LOGI(TAG, "Initialize RGB LCD panel"); ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle)); ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle)); ESP_LOGI(TAG, "Free internal heap: %d", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); ESP_LOGI(TAG, "Free SPIRAM heap: %d", heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); ESP_LOGI(TAG, "Initialize LVGL library"); lv_init(); lv_display_t *disp = lv_display_create(EXAMPLE_LCD_H_RES, EXAMPLE_LCD_V_RES); disp->user_data=panel_handle; lv_display_set_flush_cb(disp, example_lvgl_flush_cb); void *buf1 = NULL; void *buf2 = NULL; const size_t buf_pixels = example_lvgl_get_buffers(panel_handle, &buf1, &buf2); lv_display_set_buffers(disp, buf1, buf2, EXAMPLE_LCD_H_RES * 10 * sizeof(lv_color_t), LV_DISP_RENDER_MODE_PARTIAL); lvgl_mux = xSemaphoreCreateRecursiveMutex(); assert(lvgl_mux); /* lv_sdl_mouse_create(); lv_sdl_keyboard_create(); lv_sdl_mousewheel_create(); lv_sdl_mousewheel_create(); */ ESP_LOGI(TAG, "Install LVGL tick timer"); // Tick interface for LVGL (using esp_timer to generate 2ms periodic event) const esp_timer_create_args_t lvgl_tick_timer_args = { .callback = &example_increase_lvgl_tick, .name = "lvgl_tick"}; esp_timer_handle_t lvgl_tick_timer = NULL; ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer)); ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000)); ESP_LOGI(TAG, "Create LVGL task"); xTaskCreate(example_lvgl_port_task, "LVGL", EXAMPLE_LVGL_TASK_STACK_SIZE, NULL, EXAMPLE_LVGL_TASK_PRIORITY, NULL); xTaskCreate(drawIhm, "LVGL", 128 * 1024, getIHMQueueHandle(), 3, NULL); //initialise_weather_data_retrieval(20, domotic_event_group); printf("<<< end app_main()\n"); }