From ffe2c1528e78dc205b457e76daa02340b602b1d5 Mon Sep 17 00:00:00 2001 From: "Kenji Mouri (Qi Lu)" Date: Fri, 10 Nov 2023 20:21:30 +0800 Subject: [PATCH] feat(osal): add Windows support (#4783) --- Kconfig | 1 + lv_conf_template.h | 1 + src/lv_conf_internal.h | 1 + src/misc/lv_types.h | 1 + src/osal/lv_os.h | 2 + src/osal/lv_windows.c | 215 +++++++++++++++++++++++++++++++++++++++++ src/osal/lv_windows.h | 54 +++++++++++ 7 files changed, 275 insertions(+) create mode 100644 src/osal/lv_windows.c create mode 100644 src/osal/lv_windows.h diff --git a/Kconfig b/Kconfig index 6a1b15df5..b15d6d0d7 100644 --- a/Kconfig +++ b/Kconfig @@ -180,6 +180,7 @@ menu "LVGL configuration" 2:LV_OS_FREERTOS 3:LV_OS_CMSIS_RTOS2 4:LV_OS_RTTHREAD + 5:LV_OS_WINDOWS 255:LV_OS_CUSTOM config LV_USE_DRAW_SW diff --git a/lv_conf_template.h b/lv_conf_template.h index c854bdb8d..817131510 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -135,6 +135,7 @@ * - LV_OS_FREERTOS * - LV_OS_CMSIS_RTOS2 * - LV_OS_RTTHREAD + * - LV_OS_WINDOWS * - LV_OS_CUSTOM */ #define LV_USE_OS LV_OS_NONE diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 8483fe984..624fa2dcd 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -333,6 +333,7 @@ * - LV_OS_FREERTOS * - LV_OS_CMSIS_RTOS2 * - LV_OS_RTTHREAD + * - LV_OS_WINDOWS * - LV_OS_CUSTOM */ #ifndef LV_USE_OS #ifdef CONFIG_LV_USE_OS diff --git a/src/misc/lv_types.h b/src/misc/lv_types.h index ecfc12d97..05a247bab 100644 --- a/src/misc/lv_types.h +++ b/src/misc/lv_types.h @@ -37,6 +37,7 @@ extern "C" { #define LV_OS_FREERTOS 2 #define LV_OS_CMSIS_RTOS2 3 #define LV_OS_RTTHREAD 4 +#define LV_OS_WINDOWS 5 #define LV_OS_CUSTOM 255 #define LV_STDLIB_BUILTIN 0 diff --git a/src/osal/lv_os.h b/src/osal/lv_os.h index 2b007af11..9b3254fc2 100644 --- a/src/osal/lv_os.h +++ b/src/osal/lv_os.h @@ -32,6 +32,8 @@ extern "C" { #include "lv_cmsis_rtos2.h" #elif LV_USE_OS == LV_OS_RTTHREAD #include "lv_rtthread.h" +#elif LV_USE_OS == LV_OS_WINDOWS +#include "lv_windows.h" #elif LV_USE_OS == LV_OS_CUSTOM #include LV_OS_CUSTOM_INCLUDE #endif diff --git a/src/osal/lv_windows.c b/src/osal/lv_windows.c new file mode 100644 index 000000000..0d6a33d66 --- /dev/null +++ b/src/osal/lv_windows.c @@ -0,0 +1,215 @@ +/** + * @file lv_windows.c + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_os.h" + +#if LV_USE_OS == LV_OS_WINDOWS + +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + void (*callback)(void *); + void * user_data; +} lv_thread_init_data_t; + +/********************** + * STATIC PROTOTYPES + **********************/ + +static unsigned __stdcall thread_start_routine(void * parameter); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +lv_result_t lv_thread_init( + lv_thread_t * thread, + lv_thread_prio_t prio, + void (*callback)(void *), + size_t stack_size, + void * user_data) +{ + if(!thread) { + return LV_RESULT_INVALID; + } + + static const int prio_map[] = { + [LV_THREAD_PRIO_LOWEST] = THREAD_PRIORITY_LOWEST, + [LV_THREAD_PRIO_LOW] = THREAD_PRIORITY_BELOW_NORMAL, + [LV_THREAD_PRIO_MID] = THREAD_PRIORITY_NORMAL, + [LV_THREAD_PRIO_HIGH] = THREAD_PRIORITY_ABOVE_NORMAL, + [LV_THREAD_PRIO_HIGHEST] = THREAD_PRIORITY_HIGHEST, + }; + + lv_thread_init_data_t * init_data = + (lv_thread_init_data_t *)(malloc( + sizeof(lv_thread_init_data_t))); + if(!init_data) { + return LV_RESULT_INVALID; + } + init_data->callback = callback; + init_data->user_data = user_data; + + /* + Reference: https://learn.microsoft.com/en-us/windows/win32/api + /processthreadsapi/nf-processthreadsapi-createthread + + A thread in an executable that calls the C run-time library (CRT) should + use the _beginthreadex and _endthreadex functions for thread management + rather than CreateThread and ExitThread; this requires the use of the + multithreaded version of the CRT. If a thread created using CreateThread + calls the CRT, the CRT may terminate the process in low-memory conditions. + */ + *thread = (HANDLE)(_beginthreadex( + NULL, + (unsigned)(stack_size), + thread_start_routine, + init_data, + 0, + NULL)); + if(!*thread) { + return LV_RESULT_INVALID; + } + + /* + Try to set the thread priority. (Not mandatory for creating a new thread.) + */ + SetThreadPriority(*thread, prio_map[prio]); + + return LV_RESULT_OK; +} + +lv_result_t lv_thread_delete(lv_thread_t * thread) +{ + lv_result_t result = LV_RESULT_OK; + + if(!TerminateThread(thread, 0)) { + result = LV_RESULT_INVALID; + } + + CloseHandle(thread); + + return result; +} + +lv_result_t lv_mutex_init(lv_mutex_t * mutex) +{ + InitializeCriticalSection(mutex); + return LV_RESULT_OK; +} + +lv_result_t lv_mutex_lock(lv_mutex_t * mutex) +{ + EnterCriticalSection(mutex); + return LV_RESULT_OK; +} + +lv_result_t lv_mutex_lock_isr(lv_mutex_t * mutex) +{ + EnterCriticalSection(mutex); + return LV_RESULT_OK; +} + +lv_result_t lv_mutex_unlock(lv_mutex_t * mutex) +{ + LeaveCriticalSection(mutex); + return LV_RESULT_OK; +} + +lv_result_t lv_mutex_delete(lv_mutex_t * mutex) +{ + DeleteCriticalSection(mutex); + return LV_RESULT_OK; +} + +lv_result_t lv_thread_sync_init(lv_thread_sync_t * sync) +{ + if(!sync) { + return LV_RESULT_INVALID; + } + + InitializeCriticalSection(&sync->cs); + InitializeConditionVariable(&sync->cv); + + return LV_RESULT_OK; +} + +lv_result_t lv_thread_sync_wait(lv_thread_sync_t * sync) +{ + if(!sync) { + return LV_RESULT_INVALID; + } + + EnterCriticalSection(&sync->cs); + while(!sync->v) { + SleepConditionVariableCS(&sync->cv, &sync->cs, INFINITE); + } + sync->v = false; + LeaveCriticalSection(&sync->cs); + + return LV_RESULT_OK; +} + +lv_result_t lv_thread_sync_signal(lv_thread_sync_t * sync) +{ + if(!sync) { + return LV_RESULT_INVALID; + } + + EnterCriticalSection(&sync->cs); + sync->v = true; + WakeConditionVariable(&sync->cv); + LeaveCriticalSection(&sync->cs); + + return LV_RESULT_OK; +} + +lv_result_t lv_thread_sync_delete(lv_thread_sync_t * sync) +{ + if(!sync) { + return LV_RESULT_INVALID; + } + + DeleteCriticalSection(&sync->cs); + + return LV_RESULT_OK; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static unsigned __stdcall thread_start_routine(void * parameter) +{ + lv_thread_init_data_t * init_data = (lv_thread_init_data_t *)(parameter); + if(init_data) { + init_data->callback(init_data->user_data); + free(init_data); + } + + return 0; +} + +#endif /*LV_USE_OS == LV_OS_WINDOWS*/ diff --git a/src/osal/lv_windows.h b/src/osal/lv_windows.h new file mode 100644 index 000000000..fd930e872 --- /dev/null +++ b/src/osal/lv_windows.h @@ -0,0 +1,54 @@ +/** + * @file lv_windows.h + * + */ + +#ifndef LV_WINDOWS_H +#define LV_WINDOWS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#if LV_USE_OS == LV_OS_WINDOWS + +#include +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef HANDLE lv_thread_t; + +typedef CRITICAL_SECTION lv_mutex_t; + +typedef struct { + CRITICAL_SECTION cs; + CONDITION_VARIABLE cv; + bool v; +} lv_thread_sync_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_OS == LV_OS_WINDOWS*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_WINDOWS_H*/