Implement LVGL task for Windows GDI

This commit is contained in:
Kuba Szczodrzyński 2024-02-07 19:30:17 +01:00
parent d0e383e398
commit a884fbf705
No known key found for this signature in database
GPG Key ID: 43037AC62A600562
7 changed files with 87 additions and 18 deletions

View File

@ -30,6 +30,9 @@ class BaseDevice {
public: public:
bool has_battery = false; bool has_battery = false;
bool has_backligth_control = true; bool has_backligth_control = true;
#if HASP_TARGET_PC
bool pc_is_running = true;
#endif
virtual void reboot() virtual void reboot()
{} {}

View File

@ -75,6 +75,10 @@ void TftSdl::init(int32_t w, int h)
* You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about how much time were elapsed * You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about how much time were elapsed
* Create an SDL thread to do this*/ * Create an SDL thread to do this*/
SDL_CreateThread(tick_thread, "tick", NULL); SDL_CreateThread(tick_thread, "tick", NULL);
#if HASP_USE_LVGL_TASK
#error "SDL2 LVGL task is not implemented"
#endif
} }
void TftSdl::show_info() void TftSdl::show_info()
{ {

View File

@ -13,6 +13,7 @@
#include "dev/device.h" #include "dev/device.h"
#include "hasp_debug.h" #include "hasp_debug.h"
#include "hasp_gui.h"
#ifdef HASP_CUSTOMIZE_BOOTLOGO #ifdef HASP_CUSTOMIZE_BOOTLOGO
#include "custom/bootlogo.h" // Sketch tab header for xbm images #include "custom/bootlogo.h" // Sketch tab header for xbm images
@ -48,21 +49,66 @@ int32_t TftWin32Drv::height()
return _height; return _height;
} }
static void win32_message_loop(lv_task_t* param)
{
MSG Message;
#if HASP_USE_LVGL_TASK
while(haspDevice.pc_is_running && GetMessageW(&Message, NULL, 0, 0)) {
TranslateMessage(&Message);
DispatchMessageW(&Message);
}
// apparently GetMessageW doesn't deliver WM_QUIT
haspDevice.pc_is_running = false;
#else
BOOL Result = PeekMessageW(&Message, NULL, 0, 0, TRUE);
if(Result != 0 && Result != -1) {
TranslateMessage(&Message);
DispatchMessageW(&Message);
if(Message.message == WM_QUIT) haspDevice.pc_is_running = false;
}
#endif
}
static DWORD gui_entrypoint(HANDLE semaphore)
{
/* Add a display
* Use the 'win32drv' driver which creates window on PC's monitor to simulate a display
* The following input devices are handled: mouse, keyboard, mousewheel */
lv_win32_init(0, SW_SHOWNORMAL, haspTft.width(), haspTft.height(), 0);
lv_win32_set_title(haspDevice.get_hostname());
#if HASP_USE_LVGL_TASK
// let the init() function continue
ReleaseSemaphore(semaphore, 1, NULL);
// run the LVGL task as a thread
HANDLE thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)gui_task, NULL, 0, NULL);
// run a blocking message loop on this thread
win32_message_loop(NULL);
// wait for the LVGL task now
WaitForSingleObject(thread, 4000);
#else
// create a LVGL tick thread
CreateThread(NULL, 0, tick_thread, NULL, 0, NULL);
// create a LVGL task for the message loop
lv_task_create(win32_message_loop, 5, LV_TASK_PRIO_HIGHEST, NULL);
#endif
return 0;
}
void TftWin32Drv::init(int32_t w, int h) void TftWin32Drv::init(int32_t w, int h)
{ {
_width = w; _width = w;
_height = h; _height = h;
/* Add a display #if HASP_USE_LVGL_TASK
* Use the 'win32drv' driver which creates window on PC's monitor to simulate a display // run a thread for creating the window and running the message loop
* The following input devices are handled: mouse, keyboard, mousewheel */ HANDLE semaphore = CreateSemaphore(NULL, 0, 1, NULL);
lv_win32_init(0, SW_SHOWNORMAL, w, h, 0); HANDLE thread = CreateThread(NULL, 0, gui_entrypoint, semaphore, 0, NULL);
lv_win32_set_title(haspDevice.get_hostname()); WaitForSingleObject(semaphore, INFINITE);
#else
/* Tick init. // do not use the gui_task(), just init the GUI and return
* You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about how much time were elapsed gui_entrypoint(NULL);
* Create a Windows thread to do this*/ #endif
CreateThread(NULL, 0, tick_thread, NULL, 0, NULL);
} }
void TftWin32Drv::show_info() void TftWin32Drv::show_info()
{ {

View File

@ -382,23 +382,34 @@ void guiEverySecond(void)
// nothing // nothing
} }
#if defined(ESP32) && defined(HASP_USE_ESP_MQTT)
#if HASP_USE_LVGL_TASK == 1 #if HASP_USE_LVGL_TASK == 1
static void gui_task(void* args) void gui_task(void* args)
{ {
LOG_TRACE(TAG_GUI, "Start to run LVGL"); LOG_TRACE(TAG_GUI, "Start to run LVGL");
while(1) { while(haspDevice.pc_is_running) {
// no idea what MQTT has to do with LVGL - the #if is copied from the code below
#if defined(ESP32) && defined(HASP_USE_ESP_MQTT)
/* Try to take the semaphore, call lvgl related function on success */ /* Try to take the semaphore, call lvgl related function on success */
// if(pdTRUE == xSemaphoreTake(xGuiSemaphore, pdMS_TO_TICKS(10))) {
if(pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY)) { if(pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY)) {
lv_task_handler(); lv_task_handler();
xSemaphoreGive(xGuiSemaphore); xSemaphoreGive(xGuiSemaphore);
vTaskDelay(pdMS_TO_TICKS(5)); vTaskDelay(pdMS_TO_TICKS(5));
} }
#else
// optimize lv_task_handler() by actually using the returned delay value
auto time_start = millis();
uint32_t sleep_time = lv_task_handler();
delay(sleep_time);
auto time_end = millis();
lv_tick_inc(time_end - time_start);
#endif
} }
} }
#endif // HASP_USE_LVGL_TASK
#if defined(ESP32) && defined(HASP_USE_ESP_MQTT)
#if HASP_USE_LVGL_TASK == 1
esp_err_t gui_setup_lvgl_task() esp_err_t gui_setup_lvgl_task()
{ {
#if CONFIG_FREERTOS_UNICORE == 0 #if CONFIG_FREERTOS_UNICORE == 0

View File

@ -60,6 +60,11 @@ uint32_t guiScreenshotEtag();
void gui_flush_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p); void gui_flush_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p);
void gui_antiburn_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p); void gui_antiburn_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p);
/* ===== Main LVGL Task ===== */
#if HASP_USE_LVGL_TASK == 1
void gui_task(void* args);
#endif
/* ===== Locks ===== */ /* ===== Locks ===== */
#ifdef ESP32 #ifdef ESP32
IRAM_ATTR bool gui_acquire(TickType_t timeout); IRAM_ATTR bool gui_acquire(TickType_t timeout);
@ -73,4 +78,4 @@ bool guiGetConfig(const JsonObject& settings);
bool guiSetConfig(const JsonObject& settings); bool guiSetConfig(const JsonObject& settings);
#endif // HASP_USE_CONFIG #endif // HASP_USE_CONFIG
#endif // HASP_GUI_H #endif // HASP_GUI_H

View File

@ -189,8 +189,7 @@ int main(int argc, char* argv[])
loop(); loop();
} }
#elif USE_WIN32DRV #elif USE_WIN32DRV
extern bool lv_win32_quit_signal; while(haspDevice.pc_is_running) {
while(!lv_win32_quit_signal) {
loop(); loop();
} }
#endif #endif

View File

@ -29,6 +29,7 @@ build_flags =
-D HASP_USE_JPGDECODE=0 -D HASP_USE_JPGDECODE=0
-D HASP_USE_MQTT=1 -D HASP_USE_MQTT=1
-D HASP_USE_SYSLOG=0 -D HASP_USE_SYSLOG=0
-D HASP_USE_LVGL_TASK=1
-D MQTT_MAX_PACKET_SIZE=2048 -D MQTT_MAX_PACKET_SIZE=2048
-D HASP_ATTRIBUTE_FAST_MEM= -D HASP_ATTRIBUTE_FAST_MEM=
-D IRAM_ATTR= ; No IRAM_ATTR available -D IRAM_ATTR= ; No IRAM_ATTR available