移动文件夹

This commit is contained in:
不吃油炸鸡
2026-02-19 12:58:19 +08:00
parent c79943a647
commit a8cb722a6f
1199 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,195 @@
/**
* @file lv_cmsis_rtos2.c
*
*/
/*
* Copyright (C) 2023 Arm Limited or its affiliates. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*********************
* INCLUDES
*********************/
#include "lv_os.h"
#if LV_USE_OS == LV_OS_CMSIS_RTOS2
#include "../misc/lv_log.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* 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)
{
static const osPriority_t prio_map[] = {
[LV_THREAD_PRIO_LOWEST] = osPriorityLow,
[LV_THREAD_PRIO_LOW] = osPriorityBelowNormal,
[LV_THREAD_PRIO_MID] = osPriorityNormal,
[LV_THREAD_PRIO_HIGH] = osPriorityHigh,
[LV_THREAD_PRIO_HIGHEST] = osPriorityRealtime7,
};
osThreadAttr_t c_tThreadAttribute = {
.stack_size = stack_size,
.priority = prio_map[prio],
};
*thread = osThreadNew(callback, user_data, &c_tThreadAttribute);
if(NULL == *thread) {
LV_LOG_WARN("Error: Failed to create a cmsis-rtos2 thread.");
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_thread_delete(lv_thread_t * thread)
{
osThreadDetach(*thread);
osStatus_t status = osThreadTerminate(*thread);
if(status == osOK) {
return LV_RESULT_OK;
}
return LV_RESULT_INVALID;
}
lv_result_t lv_mutex_init(lv_mutex_t * mutex)
{
const osMutexAttr_t Thread_Mutex_attr = {
"LVGLMutex",
osMutexRecursive | osMutexPrioInherit | osMutexRobust,
};
*mutex = osMutexNew(&Thread_Mutex_attr);
if(*mutex == NULL) {
LV_LOG_WARN("Error: failed to create cmsis-rtos mutex");
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_mutex_lock(lv_mutex_t * mutex)
{
osStatus_t status = osMutexAcquire(*mutex, 0U);
if(status != osOK) {
LV_LOG_WARN("Error: failed to lock cmsis-rtos2 mutex %d", (int)status);
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_mutex_lock_isr(lv_mutex_t * mutex)
{
osStatus_t status = osMutexAcquire(*mutex, 0U);
if(status != osOK) {
LV_LOG_WARN("Error: failed to lock cmsis-rtos2 mutex in an ISR %d", (int)status);
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_mutex_unlock(lv_mutex_t * mutex)
{
osStatus_t status = osMutexRelease(*mutex);
if(status != osOK) {
LV_LOG_WARN("Error: failed to release cmsis-rtos2 mutex %d", (int)status);
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_mutex_delete(lv_mutex_t * mutex)
{
osStatus_t status = osMutexDelete(*mutex);
if(status != osOK) {
LV_LOG_WARN("Error: failed to delete cmsis-rtos2 mutex %d", (int)status);
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_init(lv_thread_sync_t * sync)
{
*sync = osEventFlagsNew(NULL);
if(NULL == *sync) {
LV_LOG_WARN("Error: failed to create a cmsis-rtos2 EventFlag");
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_wait(lv_thread_sync_t * sync)
{
uint32_t ret = osEventFlagsWait(*sync, 0x01, osFlagsWaitAny, osWaitForever);
if(ret & (1 << 31)) {
LV_LOG_WARN("Error: failed to wait a cmsis-rtos2 EventFlag %d", ret);
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_signal(lv_thread_sync_t * sync)
{
uint32_t ret = osEventFlagsSet(*sync, 0x01);
if(ret & (1 << 31)) {
LV_LOG_WARN("Error: failed to set a cmsis-rtos2 EventFlag %d", ret);
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * sync)
{
return lv_thread_sync_signal(sync);
}
lv_result_t lv_thread_sync_delete(lv_thread_sync_t * sync)
{
osStatus_t status = osEventFlagsDelete(*sync);
if(status != osOK) {
LV_LOG_WARN("Error: failed to delete a cmsis-rtos2 EventFlag %d", (int)status);
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_OS == LV_OS_CMSIS_RTOS2*/

View File

@@ -0,0 +1,53 @@
/**
* @file lv_cmsis_rtos2.h
*
*/
/*
* Copyright (C) 2023 Arm Limited or its affiliates. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef LV_CMSIS_RTOS2_H
#define LV_CMSIS_RTOS2_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#if LV_USE_OS == LV_OS_CMSIS_RTOS2
#include "cmsis_os2.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef osThreadId_t lv_thread_t;
typedef osMutexId_t lv_mutex_t;
typedef osEventFlagsId_t lv_thread_sync_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
#endif /*LV_USE_OS == LV_OS_CMSIS_RTOS2*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_OS_CMSIS_RTOS2*/

View File

@@ -0,0 +1,563 @@
/**
* @file lv_freertos.c
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
/*********************
* INCLUDES
*********************/
#include "lv_os.h"
#if LV_USE_OS == LV_OS_FREERTOS
#include "atomic.h"
#include "../tick/lv_tick.h"
#include "../misc/lv_log.h"
#include "../core/lv_global.h"
/*********************
* DEFINES
*********************/
#define ulMAX_COUNT 10U
#ifndef pcTASK_NAME
#define pcTASK_NAME "lvglDraw"
#endif
#define globals LV_GLOBAL_DEFAULT()
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void prvRunThread(void * pxArg);
static void prvMutexInit(lv_mutex_t * pxMutex);
static void prvCheckMutexInit(lv_mutex_t * pxMutex);
static void prvCondInit(lv_thread_sync_t * pxCond);
static void prvCheckCondInit(lv_thread_sync_t * pxCond);
static void prvCheckCondInitIsr(lv_thread_sync_t * pxCond);
#if !LV_USE_FREERTOS_TASK_NOTIFY
static void prvTestAndDecrement(lv_thread_sync_t * pxCond,
uint32_t ulLocalWaitingThreads);
#endif
/**********************
* STATIC VARIABLES
**********************/
#if (ESP_PLATFORM)
static portMUX_TYPE critSectionMux = portMUX_INITIALIZER_UNLOCKED;
#endif
/**********************
* MACROS
**********************/
#if (ESP_PLATFORM)
#define _enter_critical() taskENTER_CRITICAL(&critSectionMux);
#define _exit_critical() taskEXIT_CRITICAL(&critSectionMux);
#define _enter_critical_isr() taskENTER_CRITICAL_FROM_ISR();
#define _exit_critical_isr(x) taskEXIT_CRITICAL_FROM_ISR(x);
#else
#define _enter_critical() taskENTER_CRITICAL();
#define _exit_critical() taskEXIT_CRITICAL();
#define _enter_critical_isr() taskENTER_CRITICAL_FROM_ISR();
#define _exit_critical_isr(x) taskEXIT_CRITICAL_FROM_ISR(x);
#endif
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_result_t lv_thread_init(lv_thread_t * pxThread, lv_thread_prio_t xSchedPriority,
void (*pvStartRoutine)(void *), size_t usStackSize,
void * xAttr)
{
pxThread->pTaskArg = xAttr;
pxThread->pvStartRoutine = pvStartRoutine;
BaseType_t xTaskCreateStatus = xTaskCreate(
prvRunThread,
pcTASK_NAME,
(configSTACK_DEPTH_TYPE)(usStackSize / sizeof(StackType_t)),
(void *)pxThread,
tskIDLE_PRIORITY + xSchedPriority,
&pxThread->xTaskHandle);
/* Ensure that the FreeRTOS task was successfully created. */
if(xTaskCreateStatus != pdPASS) {
LV_LOG_ERROR("xTaskCreate failed!");
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_thread_delete(lv_thread_t * pxThread)
{
vTaskDelete(pxThread->xTaskHandle);
return LV_RESULT_OK;
}
lv_result_t lv_mutex_init(lv_mutex_t * pxMutex)
{
/* If mutex in uninitialized, perform initialization. */
prvCheckMutexInit(pxMutex);
return LV_RESULT_OK;
}
lv_result_t lv_mutex_lock(lv_mutex_t * pxMutex)
{
/* If mutex in uninitialized, perform initialization. */
prvCheckMutexInit(pxMutex);
BaseType_t xMutexTakeStatus = xSemaphoreTake(pxMutex->xMutex, portMAX_DELAY);
if(xMutexTakeStatus != pdTRUE) {
LV_LOG_ERROR("xSemaphoreTake failed!");
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_mutex_lock_isr(lv_mutex_t * pxMutex)
{
/* If mutex in uninitialized, perform initialization. */
prvCheckMutexInit(pxMutex);
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
BaseType_t xMutexTakeStatus = xSemaphoreTakeFromISR(pxMutex->xMutex, &xHigherPriorityTaskWoken);
if(xMutexTakeStatus != pdTRUE) {
LV_LOG_ERROR("xSemaphoreTake failed!");
return LV_RESULT_INVALID;
}
/* If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch
should be performed to ensure the interrupt returns directly to the highest
priority task. The macro used for this purpose is dependent on the port in
use and may be called portEND_SWITCHING_ISR(). */
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
return LV_RESULT_OK;
}
lv_result_t lv_mutex_unlock(lv_mutex_t * pxMutex)
{
/* If mutex in uninitialized, perform initialization. */
prvCheckMutexInit(pxMutex);
BaseType_t xMutexGiveStatus = xSemaphoreGive(pxMutex->xMutex);
if(xMutexGiveStatus != pdTRUE) {
LV_LOG_ERROR("xSemaphoreGive failed!");
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_mutex_delete(lv_mutex_t * pxMutex)
{
vSemaphoreDelete(pxMutex->xMutex);
pxMutex->xIsInitialized = pdFALSE;
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_init(lv_thread_sync_t * pxCond)
{
/* If the cond is uninitialized, perform initialization. */
prvCheckCondInit(pxCond);
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_wait(lv_thread_sync_t * pxCond)
{
lv_result_t lvRes = LV_RESULT_OK;
/* If the cond is uninitialized, perform initialization. */
prvCheckCondInit(pxCond);
#if LV_USE_FREERTOS_TASK_NOTIFY
TaskHandle_t xCurrentTaskHandle = xTaskGetCurrentTaskHandle();
_enter_critical();
BaseType_t xSyncSygnal = pxCond->xSyncSignal;
pxCond->xSyncSignal = pdFALSE;
if(xSyncSygnal == pdFALSE) {
/* The signal hasn't been sent yet. Tell the sender to notify this task */
pxCond->xTaskToNotify = xCurrentTaskHandle;
}
/* If we have a signal from the other task, we should not ask to be notified */
_exit_critical();
if(xSyncSygnal == pdFALSE) {
/* Wait for other task to notify this task. */
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
}
/* If the signal was received, no wait needs to be done */
#else
uint32_t ulLocalWaitingThreads;
/* Acquire the mutex. */
xSemaphoreTake(pxCond->xSyncMutex, portMAX_DELAY);
while(!pxCond->xSyncSignal) {
/* Increase the counter of threads blocking on condition variable, then
* release the mutex. */
/* Atomically increments thread waiting by 1, and
* stores number of threads waiting before increment. */
ulLocalWaitingThreads = Atomic_Increment_u32(&pxCond->ulWaitingThreads);
BaseType_t xMutexStatus = xSemaphoreGive(pxCond->xSyncMutex);
/* Wait on the condition variable. */
if(xMutexStatus == pdTRUE) {
BaseType_t xCondWaitStatus = xSemaphoreTake(
pxCond->xCondWaitSemaphore,
portMAX_DELAY);
/* Relock the mutex. */
xSemaphoreTake(pxCond->xSyncMutex, portMAX_DELAY);
if(xCondWaitStatus != pdTRUE) {
LV_LOG_ERROR("xSemaphoreTake(xCondWaitSemaphore) failed!");
lvRes = LV_RESULT_INVALID;
/* Atomically decrements thread waiting by 1.
* If iLocalWaitingThreads is updated by other thread(s) in between,
* this implementation guarantees to decrement by 1 based on the
* value currently in pxCond->ulWaitingThreads. */
prvTestAndDecrement(pxCond, ulLocalWaitingThreads + 1);
}
}
else {
LV_LOG_ERROR("xSemaphoreGive(xSyncMutex) failed!");
lvRes = LV_RESULT_INVALID;
/* Atomically decrements thread waiting by 1.
* If iLocalWaitingThreads is updated by other thread(s) in between,
* this implementation guarantees to decrement by 1 based on the
* value currently in pxCond->ulWaitingThreads. */
prvTestAndDecrement(pxCond, ulLocalWaitingThreads + 1);
}
}
pxCond->xSyncSignal = pdFALSE;
/* Release the mutex. */
xSemaphoreGive(pxCond->xSyncMutex);
#endif
return lvRes;
}
lv_result_t lv_thread_sync_signal(lv_thread_sync_t * pxCond)
{
/* If the cond is uninitialized, perform initialization. */
prvCheckCondInit(pxCond);
#if LV_USE_FREERTOS_TASK_NOTIFY
_enter_critical();
TaskHandle_t xTaskToNotify = pxCond->xTaskToNotify;
pxCond->xTaskToNotify = NULL;
if(xTaskToNotify == NULL) {
/* No task waiting to be notified. Send this signal for later */
pxCond->xSyncSignal = pdTRUE;
}
/* If a task is already waiting, there is no need to set the sync signal */
_exit_critical();
if(xTaskToNotify != NULL) {
/* There is a task waiting. Send a notification to it */
xTaskNotifyGive(xTaskToNotify);
}
/* If there was no task waiting to be notified, we sent a signal for it to see later. */
#else
/* Acquire the mutex. */
xSemaphoreTake(pxCond->xSyncMutex, portMAX_DELAY);
pxCond->xSyncSignal = pdTRUE;
/* Local copy of number of threads waiting. */
uint32_t ulLocalWaitingThreads = pxCond->ulWaitingThreads;
/* Test local copy of threads waiting is larger than zero. */
while(ulLocalWaitingThreads > 0) {
/* Atomically check whether the copy in memory has changed.
* If not, set the copy of threads waiting in memory to zero. */
if(ATOMIC_COMPARE_AND_SWAP_SUCCESS == Atomic_CompareAndSwap_u32(
&pxCond->ulWaitingThreads,
0,
ulLocalWaitingThreads)) {
/* Unblock all. */
for(uint32_t i = 0; i < ulLocalWaitingThreads; i++) {
xSemaphoreGive(pxCond->xCondWaitSemaphore);
}
break;
}
/* Local copy is out dated. Reload from memory and retry. */
ulLocalWaitingThreads = pxCond->ulWaitingThreads;
}
/* Release the mutex. */
xSemaphoreGive(pxCond->xSyncMutex);
#endif
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_delete(lv_thread_sync_t * pxCond)
{
#if !LV_USE_FREERTOS_TASK_NOTIFY
/* Cleanup all resources used by the cond. */
vSemaphoreDelete(pxCond->xCondWaitSemaphore);
vSemaphoreDelete(pxCond->xSyncMutex);
pxCond->ulWaitingThreads = 0;
#endif
pxCond->xSyncSignal = pdFALSE;
pxCond->xIsInitialized = pdFALSE;
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * pxCond)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* If the cond is uninitialized, perform initialization. */
prvCheckCondInitIsr(pxCond);
#if LV_USE_FREERTOS_TASK_NOTIFY
uint32_t mask = _enter_critical_isr();
TaskHandle_t xTaskToNotify = pxCond->xTaskToNotify;
pxCond->xTaskToNotify = NULL;
if(xTaskToNotify == NULL) {
/* No task waiting to be notified. Send this signal for later */
pxCond->xSyncSignal = pdTRUE;
}
/* If a task is already waiting, there is no need to set the sync signal */
_exit_critical_isr(mask);
if(xTaskToNotify != NULL) {
/* There is a task waiting. Send a notification to it */
vTaskNotifyGiveFromISR(xTaskToNotify, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
/* If there was no task waiting to be notified, we sent a signal for it to see later. */
#else
/* Enter critical section to prevent preemption. */
uint32_t mask = _enter_critical_isr();
pxCond->xSyncSignal = pdTRUE;
BaseType_t xAnyHigherPriorityTaskWoken = pdFALSE;
/* Unblock all. */
for(uint32_t i = 0; i < pxCond->ulWaitingThreads; i++) {
xSemaphoreGiveFromISR(pxCond->xCondWaitSemaphore, &xAnyHigherPriorityTaskWoken);
xHigherPriorityTaskWoken |= xAnyHigherPriorityTaskWoken;
}
_exit_critical_isr(mask);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
#endif
return LV_RESULT_OK;
}
void lv_freertos_task_switch_in(const char * name)
{
if(lv_strcmp(name, "IDLE")) globals->freertos_idle_task_running = false;
else globals->freertos_idle_task_running = true;
globals->freertos_task_switch_timestamp = lv_tick_get();
}
void lv_freertos_task_switch_out(void)
{
uint32_t elaps = lv_tick_elaps(globals->freertos_task_switch_timestamp);
if(globals->freertos_idle_task_running) globals->freertos_idle_time_sum += elaps;
else globals->freertos_non_idle_time_sum += elaps;
}
uint32_t lv_os_get_idle_percent(void)
{
if(globals->freertos_non_idle_time_sum + globals->freertos_idle_time_sum == 0) {
LV_LOG_WARN("Not enough time elapsed to provide idle percentage");
return 0;
}
uint32_t pct = (globals->freertos_idle_time_sum * 100) / (globals->freertos_idle_time_sum +
globals->freertos_non_idle_time_sum);
globals->freertos_non_idle_time_sum = 0;
globals->freertos_idle_time_sum = 0;
return pct;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void prvRunThread(void * pxArg)
{
lv_thread_t * pxThread = (lv_thread_t *)pxArg;
/* Run the thread routine. */
pxThread->pvStartRoutine((void *)pxThread->pTaskArg);
vTaskDelete(NULL);
}
static void prvMutexInit(lv_mutex_t * pxMutex)
{
pxMutex->xMutex = xSemaphoreCreateRecursiveMutex();
/* Ensure that the FreeRTOS mutex was successfully created. */
if(pxMutex->xMutex == NULL) {
LV_LOG_ERROR("xSemaphoreCreateMutex failed!");
return;
}
/* Mutex successfully created. */
pxMutex->xIsInitialized = pdTRUE;
}
static void prvCheckMutexInit(lv_mutex_t * pxMutex)
{
/* Check if the mutex needs to be initialized. */
if(pxMutex->xIsInitialized == pdFALSE) {
/* Mutex initialization must be in a critical section to prevent two threads
* from initializing it at the same time. */
_enter_critical();
/* Check again that the mutex is still uninitialized, i.e. it wasn't
* initialized while this function was waiting to enter the critical
* section. */
if(pxMutex->xIsInitialized == pdFALSE) {
prvMutexInit(pxMutex);
}
/* Exit the critical section. */
_exit_critical();
}
}
static void prvCondInit(lv_thread_sync_t * pxCond)
{
pxCond->xIsInitialized = pdTRUE;
pxCond->xSyncSignal = pdFALSE;
#if LV_USE_FREERTOS_TASK_NOTIFY
pxCond->xTaskToNotify = NULL;
#else
pxCond->xCondWaitSemaphore = xSemaphoreCreateCounting(ulMAX_COUNT, 0U);
/* Ensure that the FreeRTOS semaphore was successfully created. */
if(pxCond->xCondWaitSemaphore == NULL) {
LV_LOG_ERROR("xSemaphoreCreateCounting failed!");
return;
}
pxCond->xSyncMutex = xSemaphoreCreateMutex();
/* Ensure that the FreeRTOS mutex was successfully created. */
if(pxCond->xSyncMutex == NULL) {
LV_LOG_ERROR("xSemaphoreCreateMutex failed!");
/* Cleanup. */
vSemaphoreDelete(pxCond->xCondWaitSemaphore);
return;
}
/* Condition variable successfully created. */
pxCond->ulWaitingThreads = 0;
#endif
}
static void prvCheckCondInit(lv_thread_sync_t * pxCond)
{
/* Check if the condition variable needs to be initialized. */
if(pxCond->xIsInitialized == pdFALSE) {
/* Cond initialization must be in a critical section to prevent two
* threads from initializing it at the same time. */
_enter_critical();
/* Check again that the condition is still uninitialized, i.e. it wasn't
* initialized while this function was waiting to enter the critical
* section. */
if(pxCond->xIsInitialized == pdFALSE) {
prvCondInit(pxCond);
}
/* Exit the critical section. */
_exit_critical();
}
}
static void prvCheckCondInitIsr(lv_thread_sync_t * pxCond)
{
/* Check if the condition variable needs to be initialized. */
if(pxCond->xIsInitialized == pdFALSE) {
/* Cond initialization must be in a critical section to prevent two
* threads from initializing it at the same time. */
uint32_t mask = _enter_critical_isr();
/* Check again that the condition is still uninitialized, i.e. it wasn't
* initialized while this function was waiting to enter the critical
* section. */
if(pxCond->xIsInitialized == pdFALSE) {
prvCondInit(pxCond);
}
/* Exit the critical section. */
_exit_critical_isr(mask);
}
}
#if !LV_USE_FREERTOS_TASK_NOTIFY
static void prvTestAndDecrement(lv_thread_sync_t * pxCond,
uint32_t ulLocalWaitingThreads)
{
/* Test local copy of threads waiting is larger than zero. */
while(ulLocalWaitingThreads > 0) {
/* Atomically check whether the copy in memory has changed.
* If not, decrease the copy of threads waiting in memory. */
if(ATOMIC_COMPARE_AND_SWAP_SUCCESS == Atomic_CompareAndSwap_u32(
&pxCond->ulWaitingThreads,
ulLocalWaitingThreads - 1,
ulLocalWaitingThreads)) {
/* Signal one succeeded. Break. */
break;
}
/* Local copy may be out dated. Reload from memory and retry. */
ulLocalWaitingThreads = pxCond->ulWaitingThreads;
}
}
#endif
#endif /*LV_USE_OS == LV_OS_FREERTOS*/

View File

@@ -0,0 +1,105 @@
/**
* @file lv_freertos.h
*
*/
/**
* Copyright 2023 NXP
*
* SPDX-License-Identifier: MIT
*/
#ifndef LV_FREERTOS_H
#define LV_FREERTOS_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_os.h"
#if LV_USE_OS == LV_OS_FREERTOS
#if (ESP_PLATFORM)
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#else
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
void (*pvStartRoutine)(void *); /**< Application thread function. */
void * pTaskArg; /**< Arguments for application thread function. */
TaskHandle_t xTaskHandle; /**< FreeRTOS task handle. */
} lv_thread_t;
typedef struct {
BaseType_t xIsInitialized; /**< Set to pdTRUE if this mutex is initialized, pdFALSE otherwise. */
SemaphoreHandle_t xMutex; /**< FreeRTOS mutex. */
} lv_mutex_t;
typedef struct {
BaseType_t
xIsInitialized; /**< Set to pdTRUE if this condition variable is initialized, pdFALSE otherwise. */
BaseType_t xSyncSignal; /**< Set to pdTRUE if the thread is signaled, pdFALSE otherwise. */
#if LV_USE_FREERTOS_TASK_NOTIFY
TaskHandle_t xTaskToNotify; /**< The task waiting to be signalled. NULL if nothing is waiting. */
#else
SemaphoreHandle_t xCondWaitSemaphore; /**< Threads block on this semaphore in lv_thread_sync_wait. */
uint32_t ulWaitingThreads; /**< The number of threads currently waiting on this condition variable. */
SemaphoreHandle_t xSyncMutex; /**< Threads take this mutex before accessing the condition variable. */
#endif
} lv_thread_sync_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Set it for `traceTASK_SWITCHED_IN()` as
* `lv_freertos_task_switch_in(pxCurrentTCB->pcTaskName)`
* to save the start time stamp of a task
* @param name the name of the which is switched in
*/
void lv_freertos_task_switch_in(const char * name);
/**
* Set it for `traceTASK_SWITCHED_OUT()` as
* `lv_freertos_task_switch_out()`
* to save finish time stamp of a task
*/
void lv_freertos_task_switch_out(void);
/**
* Set it for `LV_SYSMON_GET_IDLE` to show the CPU usage
* as reported based the usage of FreeRTOS's idle task
* If it's important when a GPU is used.
* @return the idle percentage since the last call
*/
uint32_t lv_os_get_idle_percent(void);
/**********************
* MACROS
**********************/
#endif /*LV_USE_OS == LV_OS_FREERTOS*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_FREERTOS_H*/

View File

@@ -0,0 +1,169 @@
/**
* @file lv_mqx.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_os.h"
#if LV_USE_OS == LV_OS_MQX
#include "../misc/lv_log.h"
#include "../stdlib/lv_string.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* 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)
{
TASK_TEMPLATE_STRUCT task_template;
lv_memzero(&task_template, sizeof(task_template));
task_template.TASK_ADDRESS = (TASK_FPTR)callback;
task_template.TASK_STACKSIZE = stack_size;
task_template.TASK_PRIORITY = _sched_get_min_priority(0) - prio;
task_template.TASK_NAME = "lvglDraw";
task_template.CREATION_PARAMETER = (uint32_t)user_data;
*thread = _task_create(0, 0, (uint32_t)&task_template);
if(*thread == MQX_NULL_TASK_ID) {
LV_LOG_WARN("_task_create failed!");
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_thread_delete(lv_thread_t * thread)
{
_mqx_uint ret = _task_destroy(*thread);
if(ret != MQX_OK) {
LV_LOG_WARN("_task_destroy failed!");
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_mutex_init(lv_mutex_t * mutex)
{
if(MQX_OK != _mutex_init(mutex, NULL)) {
LV_LOG_WARN("create mutex failed");
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_mutex_lock(lv_mutex_t * mutex)
{
_mqx_uint ret = _mutex_lock(mutex);
if(ret != MQX_OK) {
LV_LOG_WARN("Error: %x", ret);
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_mutex_lock_isr(lv_mutex_t * mutex)
{
_mqx_uint ret = _mutex_lock(mutex);
if(ret != MQX_OK) {
LV_LOG_WARN("Error: %x", ret);
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_mutex_unlock(lv_mutex_t * mutex)
{
_mqx_uint ret = _mutex_unlock(mutex);
if(ret != MQX_OK) {
LV_LOG_WARN("Error: %x", ret);
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_mutex_delete(lv_mutex_t * mutex)
{
_mqx_uint ret = _mutex_destroy(mutex);
if(ret != MQX_OK) {
LV_LOG_WARN("Error: %x", ret);
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_init(lv_thread_sync_t * sync)
{
if(MQX_OK != _lwsem_create(sync, 0)) {
LV_LOG_WARN("create semaphore failed");
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_wait(lv_thread_sync_t * sync)
{
_mqx_uint ret = _lwsem_wait(sync);
if(ret != MQX_OK) {
LV_LOG_WARN("Error: %x", ret);
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_signal(lv_thread_sync_t * sync)
{
_mqx_uint ret = _lwsem_post(sync);
if(ret != MQX_OK) {
LV_LOG_WARN("Error: %x", ret);
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_delete(lv_thread_sync_t * sync)
{
_mqx_uint ret = _lwsem_destroy(sync);
if(ret != MQX_OK) {
LV_LOG_WARN("Error: %x", ret);
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * sync)
{
LV_UNUSED(sync);
return LV_RESULT_INVALID;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_OS == LV_OS_MQX*/

View File

@@ -0,0 +1,51 @@
/**
* @file lv_mqx.h
*
*/
#ifndef LV_MQX_H
#define LV_MQX_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_os.h"
#if LV_USE_OS == LV_OS_MQX
#include "mqx.h"
#include "mutex.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef _task_id lv_thread_t;
typedef MUTEX_STRUCT lv_mutex_t;
typedef LWSEM_STRUCT lv_thread_sync_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
#endif /*LV_USE_OS == LV_OS_MQX*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_MQX_H*/

View File

@@ -0,0 +1,71 @@
/**
* @file lv_os.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_os.h"
#include "lv_os_private.h"
#include "../core/lv_global.h"
/*********************
* DEFINES
*********************/
#define lv_general_mutex LV_GLOBAL_DEFAULT()->lv_general_mutex
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_os_init(void)
{
#if LV_USE_OS != LV_OS_NONE
lv_mutex_init(&lv_general_mutex);
#endif /*LV_USE_OS != LV_OS_NONE*/
}
void lv_lock(void)
{
#if LV_USE_OS != LV_OS_NONE
lv_mutex_lock(&lv_general_mutex);
#endif /*LV_USE_OS != LV_OS_NONE*/
}
lv_result_t lv_lock_isr(void)
{
#if LV_USE_OS != LV_OS_NONE
return lv_mutex_lock_isr(&lv_general_mutex);
#else /*LV_USE_OS != LV_OS_NONE*/
return LV_RESULT_OK;
#endif /*LV_USE_OS != LV_OS_NONE*/
}
void lv_unlock(void)
{
#if LV_USE_OS != LV_OS_NONE
lv_mutex_unlock(&lv_general_mutex);
#endif /*LV_USE_OS != LV_OS_NONE*/
}
/**********************
* STATIC FUNCTIONS
**********************/

View File

@@ -0,0 +1,186 @@
/**
* @file lv_os.h
*
*/
#ifndef LV_OS_H
#define LV_OS_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* OS OPTIONS
*********************/
/*********************
* INCLUDES
*********************/
#include "../lv_conf_internal.h"
#include "../misc/lv_types.h"
#if LV_USE_OS == LV_OS_NONE
#include "lv_os_none.h"
#elif LV_USE_OS == LV_OS_PTHREAD
#include "lv_pthread.h"
#elif LV_USE_OS == LV_OS_FREERTOS
#include "lv_freertos.h"
#elif LV_USE_OS == LV_OS_CMSIS_RTOS2
#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_MQX
#include "lv_mqx.h"
#elif LV_USE_OS == LV_OS_CUSTOM
#include LV_OS_CUSTOM_INCLUDE
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef enum {
LV_THREAD_PRIO_LOWEST,
LV_THREAD_PRIO_LOW,
LV_THREAD_PRIO_MID,
LV_THREAD_PRIO_HIGH,
LV_THREAD_PRIO_HIGHEST,
} lv_thread_prio_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/*----------------------------------------
* These functions needs to be implemented
* for specific operating systems
*---------------------------------------*/
/**
* Create a new thread
* @param thread a variable in which the thread will be stored
* @param prio priority of the thread
* @param callback function of the thread
* @param stack_size stack size in bytes
* @param user_data arbitrary data, will be available in the callback
* @return LV_RESULT_OK: success; LV_RESULT_INVALID: failure
*/
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);
/**
* Delete a thread
* @param thread the thread to delete
* @return LV_RESULT_OK: success; LV_RESULT_INVALID: failure
*/
lv_result_t lv_thread_delete(lv_thread_t * thread);
/**
* Create a mutex
* @param mutex a variable in which the thread will be stored
* @return LV_RESULT_OK: success; LV_RESULT_INVALID: failure
*/
lv_result_t lv_mutex_init(lv_mutex_t * mutex);
/**
* Lock a mutex
* @param mutex the mutex to lock
* @return LV_RESULT_OK: success; LV_RESULT_INVALID: failure
*/
lv_result_t lv_mutex_lock(lv_mutex_t * mutex);
/**
* Lock a mutex from interrupt
* @param mutex the mutex to lock
* @return LV_RESULT_OK: success; LV_RESULT_INVALID: failure
*/
lv_result_t lv_mutex_lock_isr(lv_mutex_t * mutex);
/**
* Unlock a mutex
* @param mutex the mutex to unlock
* @return LV_RESULT_OK: success; LV_RESULT_INVALID: failure
*/
lv_result_t lv_mutex_unlock(lv_mutex_t * mutex);
/**
* Delete a mutex
* @param mutex the mutex to delete
* @return LV_RESULT_OK: success; LV_RESULT_INVALID: failure
*/
lv_result_t lv_mutex_delete(lv_mutex_t * mutex);
/**
* Create a thread synchronization object
* @param sync a variable in which the sync will be stored
* @return LV_RESULT_OK: success; LV_RESULT_INVALID: failure
*/
lv_result_t lv_thread_sync_init(lv_thread_sync_t * sync);
/**
* Wait for a "signal" on a sync object
* @param sync a sync object
* @return LV_RESULT_OK: success; LV_RESULT_INVALID: failure
*/
lv_result_t lv_thread_sync_wait(lv_thread_sync_t * sync);
/**
* Send a wake-up signal to a sync object
* @param sync a sync object
* @return LV_RESULT_OK: success; LV_RESULT_INVALID: failure
*/
lv_result_t lv_thread_sync_signal(lv_thread_sync_t * sync);
/**
* Send a wake-up signal to a sync object from interrupt
* @param sync a sync object
* @return LV_RESULT_OK: success; LV_RESULT_INVALID: failure
*/
lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * sync);
/**
* Delete a sync object
* @param sync a sync object to delete
* @return LV_RESULT_OK: success; LV_RESULT_INVALID: failure
*/
lv_result_t lv_thread_sync_delete(lv_thread_sync_t * sync);
/**
* Lock LVGL's general mutex.
* LVGL is not thread safe, so a mutex is used to avoid executing multiple LVGL functions at the same time
* from different threads. It shall be called when calling LVGL functions from threads
* different than lv_timer_handler's thread. It doesn't need to be called in LVGL events because
* they are called from lv_timer_handler().
* It is called internally in lv_timer_handler().
*/
void lv_lock(void);
/**
* Same as `lv_lock()` but can be called from an interrupt.
* @return LV_RESULT_OK: success; LV_RESULT_INVALID: failure
*/
lv_result_t lv_lock_isr(void);
/**
* The pair of `lv_lock()` and `lv_lock_isr()`.
* It unlocks LVGL general mutex.
* It is called internally in lv_timer_handler().
*/
void lv_unlock(void);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_OS_H*/

View File

@@ -0,0 +1,127 @@
/**
* @file lv_os_none.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_os.h"
#if LV_USE_OS == LV_OS_NONE
#include "../misc/lv_types.h"
#include "../misc/lv_assert.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* 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)
{
LV_UNUSED(thread);
LV_UNUSED(callback);
LV_UNUSED(prio);
LV_UNUSED(stack_size);
LV_UNUSED(user_data);
LV_ASSERT(0);
return LV_RESULT_INVALID;
}
lv_result_t lv_thread_delete(lv_thread_t * thread)
{
LV_UNUSED(thread);
LV_ASSERT(0);
return LV_RESULT_INVALID;
}
lv_result_t lv_mutex_init(lv_mutex_t * mutex)
{
LV_UNUSED(mutex);
return LV_RESULT_OK;
}
lv_result_t lv_mutex_lock(lv_mutex_t * mutex)
{
LV_UNUSED(mutex);
return LV_RESULT_OK;
}
lv_result_t lv_mutex_lock_isr(lv_mutex_t * mutex)
{
LV_UNUSED(mutex);
return LV_RESULT_OK;
}
lv_result_t lv_mutex_unlock(lv_mutex_t * mutex)
{
LV_UNUSED(mutex);
return LV_RESULT_OK;
}
lv_result_t lv_mutex_delete(lv_mutex_t * mutex)
{
LV_UNUSED(mutex);
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_init(lv_thread_sync_t * sync)
{
LV_UNUSED(sync);
LV_ASSERT(0);
return LV_RESULT_INVALID;
}
lv_result_t lv_thread_sync_wait(lv_thread_sync_t * sync)
{
LV_UNUSED(sync);
LV_ASSERT(0);
return LV_RESULT_INVALID;
}
lv_result_t lv_thread_sync_signal(lv_thread_sync_t * sync)
{
LV_UNUSED(sync);
LV_ASSERT(0);
return LV_RESULT_INVALID;
}
lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * sync)
{
LV_UNUSED(sync);
LV_ASSERT(0);
return LV_RESULT_INVALID;
}
lv_result_t lv_thread_sync_delete(lv_thread_sync_t * sync)
{
LV_UNUSED(sync);
LV_ASSERT(0);
return LV_RESULT_INVALID;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_OS == LV_OS_NONE*/

View File

@@ -0,0 +1,43 @@
/**
* @file lv_os_none.h
*
*/
#ifndef LV_OS_NONE_H
#define LV_OS_NONE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#if LV_USE_OS == LV_OS_NONE
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef int lv_mutex_t;
typedef int lv_thread_t;
typedef int lv_thread_sync_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
#endif /*LV_USE_OS == LV_OS_NONE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_OS_NONE_H*/

View File

@@ -0,0 +1,47 @@
/**
* @file lv_os_private.h
*
*/
#ifndef LV_OS_PRIVATE_H
#define LV_OS_PRIVATE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* OS OPTIONS
*********************/
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Initialize the OS layer
*/
void lv_os_init(void);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_OS_PRIVATE_H*/

View File

@@ -0,0 +1,178 @@
/**
* @file lv_pthread.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_os.h"
#if LV_USE_OS == LV_OS_PTHREAD
#include <errno.h>
#include "../misc/lv_log.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void * generic_callback(void * user_data);
/**********************
* 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)
{
LV_UNUSED(prio);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, stack_size);
thread->callback = callback;
thread->user_data = user_data;
pthread_create(&thread->thread, &attr, generic_callback, thread);
return LV_RESULT_OK;
}
lv_result_t lv_thread_delete(lv_thread_t * thread)
{
int ret = pthread_join(thread->thread, NULL);
if(ret != 0) {
LV_LOG_WARN("Error: %d", ret);
return LV_RESULT_INVALID;
}
return LV_RESULT_OK;
}
lv_result_t lv_mutex_init(lv_mutex_t * mutex)
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
int ret = pthread_mutex_init(mutex, &attr);
pthread_mutexattr_destroy(&attr);
if(ret) {
LV_LOG_WARN("Error: %d", ret);
return LV_RESULT_INVALID;
}
else {
return LV_RESULT_OK;
}
}
lv_result_t lv_mutex_lock(lv_mutex_t * mutex)
{
int ret = pthread_mutex_lock(mutex);
if(ret) {
LV_LOG_WARN("Error: %d", ret);
return LV_RESULT_INVALID;
}
else {
return LV_RESULT_OK;
}
}
lv_result_t lv_mutex_lock_isr(lv_mutex_t * mutex)
{
int ret = pthread_mutex_lock(mutex);
if(ret) {
LV_LOG_WARN("Error: %d", ret);
return LV_RESULT_INVALID;
}
else {
return LV_RESULT_OK;
}
}
lv_result_t lv_mutex_unlock(lv_mutex_t * mutex)
{
int ret = pthread_mutex_unlock(mutex);
if(ret) {
LV_LOG_WARN("Error: %d", ret);
return LV_RESULT_INVALID;
}
else {
return LV_RESULT_OK;
}
}
lv_result_t lv_mutex_delete(lv_mutex_t * mutex)
{
pthread_mutex_destroy(mutex);
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_init(lv_thread_sync_t * sync)
{
pthread_mutex_init(&sync->mutex, 0);
pthread_cond_init(&sync->cond, 0);
sync->v = false;
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_wait(lv_thread_sync_t * sync)
{
pthread_mutex_lock(&sync->mutex);
while(!sync->v) {
pthread_cond_wait(&sync->cond, &sync->mutex);
}
sync->v = false;
pthread_mutex_unlock(&sync->mutex);
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_signal(lv_thread_sync_t * sync)
{
pthread_mutex_lock(&sync->mutex);
sync->v = true;
pthread_cond_signal(&sync->cond);
pthread_mutex_unlock(&sync->mutex);
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_delete(lv_thread_sync_t * sync)
{
pthread_mutex_destroy(&sync->mutex);
pthread_cond_destroy(&sync->cond);
return LV_RESULT_OK;
}
lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * sync)
{
LV_UNUSED(sync);
return LV_RESULT_INVALID;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void * generic_callback(void * user_data)
{
lv_thread_t * thread = user_data;
thread->callback(thread->user_data);
return NULL;
}
#endif /*LV_USE_OS == LV_OS_PTHREAD*/

View File

@@ -0,0 +1,57 @@
/**
* @file lv_pthread.h
*
*/
#ifndef LV_PTHREAD_H
#define LV_PTHREAD_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#if LV_USE_OS == LV_OS_PTHREAD
#include <pthread.h>
#include <semaphore.h>
#include <stdbool.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
pthread_t thread;
void (*callback)(void *);
void * user_data;
} lv_thread_t;
typedef pthread_mutex_t lv_mutex_t;
typedef struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
bool v;
} lv_thread_sync_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
#endif /*LV_USE_OS == LV_OS_PTHREAD*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_PTHREAD_H*/

View File

@@ -0,0 +1,190 @@
/**
* @file lv_rtthread.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_os.h"
#if LV_USE_OS == LV_OS_RTTHREAD
#include "../misc/lv_log.h"
/*********************
* DEFINES
*********************/
#define THREAD_TIMESLICE 20U
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* 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)
{
thread->thread = rt_thread_create("thread",
callback,
user_data,
stack_size,
prio,
THREAD_TIMESLICE);
rt_err_t ret = rt_thread_startup(thread->thread);
if(ret) {
LV_LOG_WARN("Error: %d", ret);
return LV_RESULT_INVALID;
}
else {
return LV_RESULT_OK;
}
}
lv_result_t lv_thread_delete(lv_thread_t * thread)
{
rt_err_t ret = rt_thread_delete(thread->thread);
if(ret) {
LV_LOG_WARN("Error: %d", ret);
return LV_RESULT_INVALID;
}
else {
return LV_RESULT_OK;
}
}
lv_result_t lv_mutex_init(lv_mutex_t * mutex)
{
mutex->mutex = rt_mutex_create("mutex", RT_IPC_FLAG_PRIO);
if(mutex->mutex == RT_NULL) {
LV_LOG_WARN("create mutex failed");
return LV_RESULT_INVALID;
}
else {
return LV_RESULT_OK;
}
}
lv_result_t lv_mutex_lock(lv_mutex_t * mutex)
{
rt_err_t ret = rt_mutex_take(mutex->mutex, RT_WAITING_FOREVER);
if(ret) {
LV_LOG_WARN("Error: %d", ret);
return LV_RESULT_INVALID;
}
else {
return LV_RESULT_OK;
}
}
lv_result_t lv_mutex_lock_isr(lv_mutex_t * mutex)
{
rt_err_t ret = rt_mutex_take(mutex->mutex, RT_WAITING_FOREVER);
if(ret) {
LV_LOG_WARN("Error: %d", ret);
return LV_RESULT_INVALID;
}
else {
return LV_RESULT_OK;
}
}
lv_result_t lv_mutex_unlock(lv_mutex_t * mutex)
{
rt_err_t ret = rt_mutex_release(mutex->mutex);
if(ret) {
LV_LOG_WARN("Error: %d", ret);
return LV_RESULT_INVALID;
}
else {
return LV_RESULT_OK;
}
}
lv_result_t lv_mutex_delete(lv_mutex_t * mutex)
{
rt_err_t ret = rt_mutex_delete(mutex->mutex);
if(ret) {
LV_LOG_WARN("Error: %d", ret);
return LV_RESULT_INVALID;
}
else {
return LV_RESULT_OK;
}
}
lv_result_t lv_thread_sync_init(lv_thread_sync_t * sync)
{
sync->sem = rt_sem_create("sem", 0, RT_IPC_FLAG_PRIO);
if(sync->sem == RT_NULL) {
LV_LOG_WARN("create semaphore failed");
return LV_RESULT_INVALID;
}
else {
return LV_RESULT_OK;
}
}
lv_result_t lv_thread_sync_wait(lv_thread_sync_t * sync)
{
rt_err_t ret = rt_sem_take(sync->sem, RT_WAITING_FOREVER);
if(ret) {
LV_LOG_WARN("Error: %d", ret);
return LV_RESULT_INVALID;
}
else {
return LV_RESULT_OK;
}
}
lv_result_t lv_thread_sync_signal(lv_thread_sync_t * sync)
{
rt_err_t ret = rt_sem_release(sync->sem);
if(ret) {
LV_LOG_WARN("Error: %d", ret);
return LV_RESULT_INVALID;
}
else {
return LV_RESULT_OK;
}
}
lv_result_t lv_thread_sync_delete(lv_thread_sync_t * sync)
{
rt_err_t ret = rt_sem_delete(sync->sem);
if(ret) {
LV_LOG_WARN("Error: %d", ret);
return LV_RESULT_INVALID;
}
else {
return LV_RESULT_OK;
}
}
lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * sync)
{
LV_UNUSED(sync);
return LV_RESULT_INVALID;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_OS == LV_OS_RTTHREAD*/

View File

@@ -0,0 +1,54 @@
/**
* @file lv_rtthread.h
*
*/
#ifndef LV_RTTHREAD_H
#define LV_RTTHREAD_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#if LV_USE_OS == LV_OS_RTTHREAD
#include <rtthread.h>
#include <stdbool.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
rt_thread_t thread;
} lv_thread_t;
typedef struct {
rt_mutex_t mutex;
} lv_mutex_t;
typedef struct {
rt_sem_t sem;
} lv_thread_sync_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
#endif /*LV_USE_OS == LV_OS_RTTHREAD*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_RTTHREAD_H*/

View File

@@ -0,0 +1,222 @@
/**
* @file lv_windows.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_os.h"
#if LV_USE_OS == LV_OS_WINDOWS
#include <process.h>
/*********************
* 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);
sync->v = false;
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;
}
lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * sync)
{
LV_UNUSED(sync);
return LV_RESULT_INVALID;
}
/**********************
* 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*/

View File

@@ -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 <Windows.h>
#include <stdbool.h>
/*********************
* 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*/