重新封裝FREERTOS_NRF_RTC函數,以便适配RTX4 /RTX5 / FREERTOS。
為什麼要單獨把RTC拿出來,因為不同MCU的RTC寄存器不一緻,這裡适配的是NRF52系列的。
Nordic的協定棧與RTX/RTX5沖突,因為他們都使用的SVN。(具體原因參考:[nrf51][nrf52] 移植RTX或者FreeRTOS需要注意的問題)
FreeRTOS 是一類 RTOS,設計得足夠小以在微控制器上運作——盡管它的使用不限于微控制器應用。
微控制器是一種小型且資源受限的處理器,它在單個晶片上內建了處理器本身、隻讀存儲器(ROM 或閃存)以儲存要執行的程式,以及程式所需的随機存取存儲器 (RAM)執行。通常,程式直接從隻讀存儲器中執行。
微控制器用于深度嵌入式應用程式(那些您從未真正看到處理器本身或其運作的軟體的應用程式),這些應用程式通常有非常具體和專門的工作要做。大小限制和專用終端應用程式性質很少保證使用完整的 RTOS 實作 - 或者确實使使用完整的 RTOS 實作成為可能。是以,FreeRTOS 僅提供核心實時排程功能、任務間通信、計時和同步原語。這意味着它被更準确地描述為實時核心或實時執行程式。附加功能(例如指令控制台界面或網絡堆棧)可以包含在附加元件中。
為什麼選擇 FreeRTOS?
-
可信核心
憑借久經考驗的穩健性、微小的占用空間和廣泛的裝置支援,FreeRTOS 核心受到世界領先公司的信賴,成為微控制器和小型微處理器的事實上的标準。
-
加快上市時間
通過詳細的預配置示範和物聯網 (IoT) 參考內建,無需确定如何設定項目。快速下載下傳、編譯并更快地進入市場。
-
廣泛的生态系統支援
我們的合作夥伴生态系統提供了廣泛的選擇,包括社群貢獻、專業支援以及內建的 IDE 和生産力工具。
-
長期支援的可預測性
FreeRTOS 通過長期支援 (LTS) 版本提供功能穩定性。FreeRTOS LTS 庫提供兩年的安全更新和關鍵錯誤修複。由 AWS 維護,以造福于 FreeRTOS 社群。
特征
-
小而省電的核心
大小可擴充,可用程式記憶體占用低至 9KB。一些架構包括無滴答的省電模式
-
支援 40 多種架構
一個代碼庫,适用于 40 多種 MCU 架構和 15 多種工具鍊,包括最新的 RISC-V 和 ARMv8-M(Arm Cortex-M33)微控制器
-
子產品化庫
越來越多的附加庫用于所有行業部門,包括安全的本地或雲連接配接
-
AWS 參考內建
利用經過測試的示例,其中包括安全連接配接到雲所必需的所有庫
-
MIT 許可,有選項
FreeRTOS 可在其MIT 許可下用于任何目的 。我們的戰略合作夥伴還提供 商業許可證和 安全認證。
/********************************************************************************
* @file os_api.c
* @author jianqiang.xue
* @version V1.0.0
* @date 2021-08-27
* @brief FreeRTOS Kernel V10.0.0
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include "FreeRTOS.h"
#include "FreeRTOSConfig.h"
#include "freertos_mpool.h"
#include "queue.h"
#include "semphr.h"
#include "task.h"
#include "timers.h"
/* Private Includes ----------------------------------------------------------*/
#include "cmsis_os.h"
#include "log.h"
#include "os_api.h"
/* Private Define ------------------------------------------------------------*/
#ifndef __ARM_ARCH_6M__
#define __ARM_ARCH_6M__ 0
#endif
#ifndef __ARM_ARCH_7M__
#define __ARM_ARCH_7M__ 0
#endif
#ifndef __ARM_ARCH_7EM__
#define __ARM_ARCH_7EM__ 0
#endif
#ifndef __ARM_ARCH_8M_MAIN__
#define __ARM_ARCH_8M_MAIN__ 0
#endif
#ifndef __ARM_ARCH_7A__
#define __ARM_ARCH_7A__ 0
#endif
#if ((__ARM_ARCH_7M__ == 1U) || \
(__ARM_ARCH_7EM__ == 1U) || \
(__ARM_ARCH_8M_MAIN__ == 1U))
#define IS_IRQ_MASKED() ((__get_PRIMASK() != 0U) || (__get_BASEPRI() != 0U))
#elif (__ARM_ARCH_6M__ == 1U)
#define IS_IRQ_MASKED() (__get_PRIMASK() != 0U)
#elif (__ARM_ARCH_7A__ == 1U)
/* CPSR mask bits */
#define CPSR_MASKBIT_I 0x80U
#define IS_IRQ_MASKED() ((__get_CPSR() & CPSR_MASKBIT_I) != 0U)
#else
#define IS_IRQ_MASKED() (__get_PRIMASK() != 0U)
#endif
#if (__ARM_ARCH_7A__ == 1U)
/* CPSR mode bitmasks */
#define CPSR_MODE_USER 0x10U
#define CPSR_MODE_SYSTEM 0x1FU
#define IS_IRQ_MODE() ((__get_mode() != CPSR_MODE_USER) && (__get_mode() != CPSR_MODE_SYSTEM))
#else
#define IS_IRQ_MODE() (__get_IPSR() != 0U)
#endif
#define IS_IRQ() (IS_IRQ_MODE() || (IS_IRQ_MASKED() && (KernelState == osKernelRunning)))
/* Limits */
#define MAX_BITS_TASK_NOTIFY 31U
#define MAX_BITS_EVENT_GROUPS 24U
#define THREAD_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_TASK_NOTIFY) - 1U))
#define EVENT_FLAGS_INVALID_BITS (~((1UL << MAX_BITS_EVENT_GROUPS) - 1U))
/* Kernel version and identification string definition (major.minor.rev: mmnnnrrrr dec) */
#define KERNEL_VERSION (((uint32_t)tskKERNEL_VERSION_MAJOR * 10000000UL) | \
((uint32_t)tskKERNEL_VERSION_MINOR * 10000UL) | \
((uint32_t)tskKERNEL_VERSION_BUILD * 1UL))
#define KERNEL_ID ("FreeRTOS " tskKERNEL_VERSION_NUMBER)
/* Private Typedef -----------------------------------------------------------*/
#if configUSE_TRACE_FACILITY
/* Used with the uxTaskGetSystemState() function to return the state of each task in the system. */
typedef struct
{
const char *pcTaskName; /* 指向任務名稱的指針 */
uint16_t usStackHighWaterMark; /* 自建立任務以來,為該任務保留的最小堆棧空間。 這個值越接近于零,任務就越接近于溢出它的堆棧 */
} task_stack_t;
task_stack_t os_task_stack[configThread_Quantity] = {0};
#endif
/* Timer callback information structure definition */
typedef struct {
osTimerFunc_t func;
void *arg;
} TimerCallback_t;
/* Private Macro -------------------------------------------------------------*/
/* Private Variables ---------------------------------------------------------*/
/* Kernel initialization state */
static osKernelState_t KernelState = osKernelInactive;
/*
Function macro used to retrieve semaphore count from ISR
*/
#ifndef uxSemaphoreGetCountFromISR
#define uxSemaphoreGetCountFromISR( xSemaphore ) uxQueueMessagesWaitingFromISR( ( QueueHandle_t ) ( xSemaphore ) )
#endif
// 記錄線程ID
static TaskHandle_t m_task_id[configThread_Quantity] = {0};
static uint8_t m_task_id_tick = 0;
/* Public Function Prototypes -----------------------------------------------*/
/*********************************OS_KERNEL***********************************/
os_status os_kernel_initialize(void)
{
os_status stat;
if (IS_IRQ())
{
stat = OS_ERROR_ISR;
}
else
{
if (KernelState == osKernelInactive)
{
#if defined(USE_TRACE_EVENT_RECORDER)
EvrFreeRTOSSetup(0U);
#endif
#if defined(USE_FreeRTOS_HEAP_5) && (HEAP_5_REGION_SETUP == 1)
vPortDefineHeapRegions(configHEAP_5_REGIONS);
#endif
KernelState = osKernelReady;
stat = OS_OK;
}
else
{
stat = OS_ERROR_PARAMETER;
}
}
return (stat);
}
os_status os_kernel_start(void)
{
os_status stat;
if (IS_IRQ())
{
stat = OS_ERROR_ISR;
}
else
{
if (KernelState == osKernelReady)
{
/* Change state to enable IRQ masking check */
KernelState = osKernelRunning;
/* Start the kernel scheduler */
vTaskStartScheduler();
stat = OS_OK;
}
else
{
stat = OS_ERROR_PARAMETER;
}
}
return (stat);
}
os_status os_delay(uint32_t ms)
{
if (IS_IRQ())
{
return OS_ERROR_ISR;
}
if (ms != 0)
{
vTaskDelay(ms);
}
return OS_OK;
}
os_status os_kernel_lock(void)
{
os_status lock;
if (IS_IRQ())
{
lock = OS_ERROR_ISR;
}
else
{
switch (xTaskGetSchedulerState())
{
case taskSCHEDULER_SUSPENDED:
lock = (os_status)1;
break;
case taskSCHEDULER_RUNNING:
vTaskSuspendAll();
lock = OS_OK;
break;
case taskSCHEDULER_NOT_STARTED:
default:
lock = OS_ERROR_PARAMETER;
break;
}
}
return (lock);
}
os_status os_kernel_unlock(void)
{
os_status lock;
if (IS_IRQ())
{
lock = OS_ERROR_ISR;
}
else
{
switch (xTaskGetSchedulerState())
{
case taskSCHEDULER_SUSPENDED:
lock = (os_status)1;
if (xTaskResumeAll() != pdTRUE)
{
if (xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED)
{
lock = OS_ERROR_PARAMETER;
}
}
break;
case taskSCHEDULER_RUNNING:
lock = OS_OK;
break;
case taskSCHEDULER_NOT_STARTED:
default:
lock = OS_ERROR_PARAMETER;
break;
}
}
return (lock);
}
uint32_t os_get_tick(void)
{
TickType_t ticks;
if (IS_IRQ())
{
ticks = xTaskGetTickCountFromISR();
}
else
{
ticks = xTaskGetTickCount();
}
return (ticks);
}
/************************************OS_THREAD************************************/
os_thread_id os_thread_create(const os_thread_def_t *thread_def, void *arg)
{
if (m_task_id_tick >= configThread_Quantity)
{
return NULL;
}
if (xTaskCreate((TaskFunction_t)thread_def->pthread, arg, thread_def->stacksize, NULL, thread_def->tpriority, m_task_id + m_task_id_tick))
{
m_task_id_tick++;
return (os_thread_id)m_task_id[m_task_id_tick - 1];
}
return NULL;
}
/************************************OS_TIMER************************************/
static void TimerCallback(TimerHandle_t hTimer)
{
TimerCallback_t *callb;
callb = (TimerCallback_t *)pvTimerGetTimerID(hTimer);
if (callb != NULL)
{
callb->func(callb->arg);
}
}
os_timer_id os_timer_create(const os_timer_def_t *timer_def, os_timer_t type, void *arg)
{
TimerHandle_t hTimer = NULL;
TimerCallback_t *callb = NULL;
if (!IS_IRQ() && (timer_def->ptimer != NULL))
{
/* Allocate memory to store callback function and argument */
callb = pvPortMalloc (sizeof(TimerCallback_t));
if (callb != NULL)
{
callb->func = (osTimerFunc_t)timer_def->ptimer;
callb->arg = arg;
hTimer = xTimerCreate(timer_def->timer, 1, type, callb, TimerCallback);
if ((hTimer == NULL) && (callb != NULL))
{
vPortFree(callb);
}
}
}
return ((os_timer_id)hTimer);
}
os_status os_timer_start(os_timer_id timer_id, uint32_t millisec)
{
TimerHandle_t hTimer = (TimerHandle_t)timer_id;
os_status stat;
if (IS_IRQ())
{
stat = OS_ERROR_ISR;
}
else if (hTimer == NULL)
{
stat = OS_ERROR_PARAMETER;
}
else
{
if (xTimerChangePeriod(hTimer, millisec, 0))
{
stat = OS_OK;
}
else
{
stat = OS_ERROR_RESOURCE;
}
}
return (stat);
}
os_status os_timer_stop(os_timer_id timer_id)
{
TimerHandle_t hTimer = (TimerHandle_t)timer_id;
os_status stat;
if (IS_IRQ())
{
stat = OS_ERROR_ISR;
}
else if (hTimer == NULL)
{
stat = OS_ERROR_PARAMETER;
}
else
{
if (xTimerIsTimerActive(hTimer) == (BaseType_t)false)
{
stat = OS_ERROR_RESOURCE;
}
else
{
if (xTimerStop(hTimer, 0))
{
stat = OS_OK;
}
else
{
stat = OS_ERROR_OS;
}
}
}
return (stat);
}
/************************************OS_MAIL************************************/
os_mail_qid os_mail_create(const os_mailq_def_t *queue_def, os_thread_id thread_id)
{
return 0;
}
void *os_mail_alloc(os_mail_qid queue_id, uint32_t millisec)
{
return NULL;
}
void *os_mail_clean_and_alloc(os_mail_qid queue_id, uint32_t millisec)
{
return NULL;
}
os_status os_mail_put(os_mail_qid queue_id, void *mail)
{
return OS_ERROR_OS;
}
os_event os_mail_get(os_mail_qid queue_id, uint32_t millisec, void *arg)
{
os_event event_t;
return event_t;
}
os_status os_mail_free(os_mail_qid queue_id, void *mail)
{
return OS_ERROR_OS;
}
/************************************OS_POOL************************************/
/* Static memory pool functions */
static void FreeBlock (MemPool_t *mp, void *block);
static void *AllocBlock (MemPool_t *mp);
static void *CreateBlock (MemPool_t *mp);
os_pool_id os_pool_create(const os_pool_def_t *pool_def)
{
MemPool_t *mp = NULL;
const char *name = pool_def->pool;
uint32_t sz = MEMPOOL_ARR_SIZE (pool_def->pool_sz, pool_def->item_sz);
if (IS_IRQ())
{
mp = NULL;
}
else if ((pool_def->pool_sz == 0U) || (pool_def->item_sz == 0U))
{
mp = NULL;
}
else
{
mp = pvPortMalloc(sizeof(MemPool_t));
if (mp != NULL)
{
mp->sem = xSemaphoreCreateCounting(pool_def->pool_sz, pool_def->pool_sz);
if (mp->sem != NULL)
{
mp->mem_arr = pvPortMalloc (sz);
}
}
if ((mp != NULL) && (mp->mem_arr != NULL))
{
/* Memory pool can be created */
mp->head = NULL;
mp->mem_sz = sz;
mp->name = name;
mp->bl_sz = pool_def->item_sz;
mp->bl_cnt = pool_def->pool_sz;
mp->n = 0U;
/* Set heap allocated memory flags */
mp->status = MPOOL_STATUS;
/* Control block on heap */
mp->status |= 1U;
/* Memory array on heap */
mp->status |= 2U;
}
else
{
/* Memory pool cannot be created, release allocated resources */
if (mp != NULL)
{
/* Free control block memory */
vPortFree(mp);
}
mp = NULL;
}
}
return (os_pool_id)mp;
}
void *os_pool_alloc(os_pool_id pool_id)
{
MemPool_t *mp;
void *block;
uint32_t isrm;
if (pool_id == NULL)
{
/* Invalid input parameters */
block = NULL;
}
else
{
block = NULL;
mp = (MemPool_t *)pool_id;
if ((mp->status & MPOOL_STATUS) == MPOOL_STATUS)
{
if (IS_IRQ())
{
if (xSemaphoreTakeFromISR(mp->sem, NULL) == (BaseType_t)true)
{
if ((mp->status & MPOOL_STATUS) == MPOOL_STATUS)
{
isrm = taskENTER_CRITICAL_FROM_ISR();
/* Get a block from the free-list */
block = AllocBlock(mp);
if (block == NULL)
{
/* List of free blocks is empty, 'create' new block */
block = CreateBlock(mp);
}
taskEXIT_CRITICAL_FROM_ISR(isrm);
}
}
}
else
{
if (xSemaphoreTake(mp->sem, (TickType_t)0) == (BaseType_t)true)
{
if ((mp->status & MPOOL_STATUS) == MPOOL_STATUS)
{
taskENTER_CRITICAL();
/* Get a block from the free-list */
block = AllocBlock(mp);
if (block == NULL)
{
/* List of free blocks is empty, 'create' new block */
block = CreateBlock(mp);
}
taskEXIT_CRITICAL();
}
}
}
}
}
return (block);
}
void *os_pool_calloc(os_pool_id pool_id)
{
return os_pool_alloc(pool_id);
}
os_status os_pool_free(os_pool_id pool_id, void *block)
{
MemPool_t *mp;
os_status stat;
uint32_t isrm;
BaseType_t yield;
if ((pool_id == NULL) || (block == NULL))
{
/* Invalid input parameters */
stat = OS_ERROR_PARAMETER;
}
else
{
mp = (MemPool_t *)pool_id;
if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS)
{
/* Invalid object status */
stat = OS_ERROR_RESOURCE;
}
else if ((block < (void *)&mp->mem_arr[0]) || (block > (void *)&mp->mem_arr[mp->mem_sz - 1]))
{
/* Block pointer outside of memory array area */
stat = OS_ERROR_PARAMETER;
}
else
{
stat = OS_OK;
if (IS_IRQ())
{
if (uxSemaphoreGetCountFromISR(mp->sem) == mp->bl_cnt)
{
stat = OS_ERROR_RESOURCE;
}
else
{
isrm = taskENTER_CRITICAL_FROM_ISR();
/* Add block to the list of free blocks */
FreeBlock(mp, block);
taskEXIT_CRITICAL_FROM_ISR(isrm);
yield = pdFALSE;
xSemaphoreGiveFromISR(mp->sem, &yield);
portYIELD_FROM_ISR(yield);
}
}
else
{
if (uxSemaphoreGetCount(mp->sem) == mp->bl_cnt)
{
stat = OS_ERROR_RESOURCE;
}
else
{
taskENTER_CRITICAL();
/* Add block to the list of free blocks */
FreeBlock(mp, block);
taskEXIT_CRITICAL();
xSemaphoreGive(mp->sem);
}
}
}
}
return (stat);
}
uint8_t os_pool_get_space(os_pool_id pool_id)
{
MemPool_t *mp;
uint32_t n;
if (pool_id == NULL)
{
/* Invalid input parameters */
n = 0U;
}
else
{
mp = (MemPool_t *)pool_id;
if ((mp->status & MPOOL_STATUS) != MPOOL_STATUS)
{
/* Invalid object status */
n = 0U;
}
else
{
if (IS_IRQ())
{
n = uxSemaphoreGetCountFromISR(mp->sem);
}
else
{
n = uxSemaphoreGetCount(mp->sem);
}
}
}
/* Return number of memory blocks available */
return (n);
}
/*
Create new block given according to the current block index.
*/
static void *CreateBlock(MemPool_t *mp)
{
MemPoolBlock_t *p = NULL;
if (mp->n < mp->bl_cnt)
{
/* Unallocated blocks exist, set pointer to new block */
p = (void *)(mp->mem_arr + (mp->bl_sz * mp->n));
/* Increment block index */
mp->n += 1U;
}
return (p);
}
/*
Allocate a block by reading the list of free blocks.
*/
static void *AllocBlock(MemPool_t *mp)
{
MemPoolBlock_t *p = NULL;
if (mp->head != NULL)
{
/* List of free block exists, get head block */
p = mp->head;
/* Head block is now next on the list */
mp->head = p->next;
}
return (p);
}
/*
Free block by putting it to the list of free blocks.
*/
static void FreeBlock(MemPool_t *mp, void *block)
{
MemPoolBlock_t *p = block;
/* Store current head into block memory space */
p->next = mp->head;
/* Store current block as new head */
mp->head = p;
}
/************************************OS_MSG_QUEUE************************************/
/**
* @brief [消息隊列] 建立消息隊列空間
* @note NULL
* @param queue_def : 消息隊列資訊(大小)
* @param thread_id : 線程ID(可以無視不填)
* @retval None
*/
os_message_qid os_message_create(const os_messageq_def_t *queue_def, os_thread_id thread_id)
{
QueueHandle_t hQueue = NULL;
if (!IS_IRQ() && (queue_def->queue_sz > 0U))
{
hQueue = xQueueCreate(queue_def->queue_sz, 4);
if (queue_def->attr.name);
#if (configQUEUE_REGISTRY_SIZE > 0)
if (hQueue != NULL)
{
vQueueAddToRegistry(hQueue, queue_def->attr.name);
}
#endif
}
return ((os_message_qid)hQueue);
}
/**
* @brief [消息隊列] 發送一組消息隊列資料
* @note NULL
* @param queue_id: 消息隊列ID
* @param info : 消息指針
* @param millisec: 逾時時間 0xFFFFFFFF 無限等待
* @retval None
*/
os_status os_message_put(os_message_qid queue_id, uint32_t info, uint32_t millisec)
{
QueueHandle_t hQueue = (QueueHandle_t)queue_id;
os_status stat;
BaseType_t yield;
stat = OS_OK;
if (IS_IRQ())
{
if ((hQueue == NULL) || (info == NULL) || (millisec != 0U))
{
stat = OS_ERROR_PARAMETER;
}
else
{
yield = false;
if (xQueueSendToBackFromISR(hQueue, (const void *)&info, &yield) != (BaseType_t)true)
{
stat = OS_ERROR_RESOURCE;
}
else
{
portYIELD_FROM_ISR(yield);
}
}
}
else
{
if ((hQueue == NULL) || (info == NULL))
{
stat = OS_ERROR_PARAMETER;
}
else
{
if (xQueueSendToBack(hQueue, (const void *)&info, (TickType_t)millisec) != (BaseType_t)true)
{
if (millisec != 0U)
{
stat = OS_EVENT_TIMEOUT;
}
else
{
stat = OS_ERROR_RESOURCE;
}
}
}
}
//LOG_D("os_msg_put:0x%x|0x%x", queue_id, info);
return stat;
}
/**
* @brief [消息隊列] 得到一組消息隊列資料
* @note NULL
* @param queue_id: 消息隊列ID
* @param millisec: 等待時間 0xFFFFFFFF 無限等待
* @retval None
*/
os_event os_message_get(os_message_qid queue_id, uint32_t millisec)
{
QueueHandle_t hQueue = (QueueHandle_t)queue_id;
BaseType_t yield;
uint32_t *msg_ptr;
os_event event;
event.status = OS_OK;
if (IS_IRQ())
{
if ((hQueue == NULL) || (millisec != 0U))
{
event.status = OS_ERROR_PARAMETER;
}
else
{
yield = false;
if (xQueueReceiveFromISR(hQueue, &msg_ptr, &yield) != true)
{
event.status = OS_ERROR_RESOURCE;
}
else
{
event.status = OS_EVENT_MESSAGE;
event.value.p = (void *)msg_ptr;
portYIELD_FROM_ISR(yield);
}
}
}
else
{
if (hQueue == NULL)
{
event.status = OS_ERROR_PARAMETER;
}
else
{
if (xQueueReceive(hQueue, &msg_ptr, (TickType_t)millisec) != true)
{
if (millisec != 0U)
{
event.status = OS_EVENT_TIMEOUT;
}
else
{
event.status = OS_ERROR_RESOURCE;
}
}
else
{
event.status = OS_EVENT_MESSAGE;
event.value.p = (void *)msg_ptr;
//LOG_D("os_msg_get:0x%x|0x%x", queue_id, msg_ptr);
}
}
}
return event;
}
/**
* @brief [消息隊列] 得到目前剩餘量
* @note NULL
* @param queue_id: 消息隊列ID
* @retval 傳回目前剩餘量
*/
uint8_t os_message_get_space(os_message_qid queue_id)
{
StaticQueue_t *mq = (StaticQueue_t *)queue_id;
uint32_t space;
uint32_t isrm;
if (mq == NULL)
{
space = 0U;
}
else if (IS_IRQ())
{
isrm = taskENTER_CRITICAL_FROM_ISR();
/* space = pxQueue->uxLength - pxQueue->uxMessagesWaiting; */
space = mq->uxDummy4[1] - mq->uxDummy4[0];
taskEXIT_CRITICAL_FROM_ISR(isrm);
}
else
{
space = (uint32_t)uxQueueSpacesAvailable((QueueHandle_t)mq);
}
return (uint8_t)space;
}
/**
* @brief [消息隊列] 得到目前使用量
* @note NULL
* @param queue_id: 消息隊列ID
* @retval 傳回目前使用量
*/
uint8_t os_message_get_count(os_message_qid queue_id)
{
QueueHandle_t hQueue = (QueueHandle_t)queue_id;
UBaseType_t count;
if (hQueue == NULL)
{
count = 0U;
}
else if (IS_IRQ())
{
count = uxQueueMessagesWaitingFromISR(hQueue);
}
else
{
count = uxQueueMessagesWaiting(hQueue);
}
return count;
}
/************************************OS_SIGNAL************************************/
int32_t isr_signal_set(os_thread_id thread_id, int32_t signals)
{
return os_signal_set(thread_id, signals);
}
int32_t os_signal_set(os_thread_id thread_id, int32_t signals)
{
TaskHandle_t hTask = (TaskHandle_t)thread_id;
uint32_t rflags;
BaseType_t yield;
// LOG_D("os_signal_set:0x%x\r\n", (uint32_t)hTask);
if ((hTask == NULL) || ((signals & THREAD_FLAGS_INVALID_BITS) != 0U))
{
rflags = (uint32_t)OS_ERROR_PARAMETER;
}
else
{
rflags = (uint32_t)OS_OK;
if (IS_IRQ())
{
yield = false;
(void)xTaskNotifyFromISR(hTask, signals, eSetBits, &yield);
(void)xTaskNotifyAndQueryFromISR(hTask, 0, eNoAction, &rflags, NULL);
portYIELD_FROM_ISR(yield);
}
else
{
(void)xTaskNotify(hTask, signals, eSetBits);
(void)xTaskNotifyAndQuery(hTask, 0, eNoAction, &rflags);
}
}
// LOG_D("os_signal_set_rflags:0x%x\r\n", (uint32_t)rflags);
/* Return flags after setting */
return (rflags);
}
int32_t os_signal_clear(os_thread_id thread_id, int32_t signals)
{
TaskHandle_t hTask = (TaskHandle_t)thread_id;
uint32_t rflags, cflags;
if (IS_IRQ())
{
rflags = (uint32_t)OS_ERROR_ISR;
}
else if ((signals & THREAD_FLAGS_INVALID_BITS) != 0U)
{
rflags = (uint32_t)OS_ERROR_PARAMETER;
}
else
{
if (xTaskNotifyAndQuery(hTask, 0, eNoAction, &cflags) == (BaseType_t)true)
{
rflags = cflags;
cflags &= ~signals;
if (xTaskNotify(hTask, cflags, eSetValueWithOverwrite) != (BaseType_t)true)
{
rflags = (uint32_t)OS_ERROR_OS;
}
}
else
{
rflags = (uint32_t)OS_ERROR_OS;
}
}
/* Return flags before clearing */
return (rflags);
}
// signals = 0,則等待任意信号.
os_event os_signal_wait(int32_t signals, uint32_t millisec)
{
BaseType_t rval;
os_event event_t;
if (IS_IRQ())
{
event_t.status = OS_ERROR_ISR;
}
else if ((signals & THREAD_FLAGS_INVALID_BITS) != 0U)
{
event_t.status = OS_ERROR_PARAMETER;
}
else
{
rval = xTaskNotifyWait(signals, 0xFFFFFFFF, (uint32_t *)&(event_t.value.signals), millisec);
if (rval == true)
{
event_t.status = OS_EVENT_SIGNAL;
}
else
{
event_t.status = OS_EVENT_TIMEOUT;
}
}
/* Return flags before clearing */
return (event_t);
}
/**
* @brief 得到每個任務堆棧空間
* @note 任務名 狀态 ID 優先級 堆棧 CPU使用率
* 任務狀态: r-運作 R-就緒 B-阻塞 S-挂起 D-删除
* @retval None
*/
void get_task_info(void)
{
#if configUSE_TRACE_FACILITY
uint32_t ulTotalRunTime;
uint8_t uxArraySize = 0;
/* 擷取任務總數目 */
uxArraySize = uxTaskGetNumberOfTasks();
if (uxArraySize > configThread_Quantity)
{
return;
}
TaskStatus_t pxTaskStatusArray[configThread_Quantity] = {0};
/* 擷取每個任務的狀态資訊 */
uxArraySize = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, &ulTotalRunTime);
for (uint8_t i = 0; i < uxArraySize; i++)
{
if (pxTaskStatusArray[i].xTaskNumber < configThread_Quantity)
{
os_task_stack[pxTaskStatusArray[i].xTaskNumber].pcTaskName = pxTaskStatusArray[i].pcTaskName;
os_task_stack[pxTaskStatusArray[i].xTaskNumber].usStackHighWaterMark = pxTaskStatusArray[i].usStackHighWaterMark;
}
}
#endif
}
/********************************************************************************
* @file os_api.h
* @author jianqiang.xue
* @version V1.0.0
* @date 2021-04-03
* @brief NULL
********************************************************************************/
#include <stdint.h>
#include "cmsis_os.h"
/// Timeout value.
#define OS_WAIT_FOREVER 0xFFFFFFFFU ///< wait forever timeout value
/************************************OS_KERNEL************************************/
typedef enum {
OS_OK = 0, ///< function completed; no error or event occurred.
OS_EVENT_SIGNAL = 0x08, ///< function completed; signal event occurred.
OS_EVENT_MESSAGE = 0x10, ///< function completed; message event occurred.
OS_EVENT_MAIL = 0x20, ///< function completed; mail event occurred.
OS_EVENT_TIMEOUT = 0x40, ///< function completed; timeout occurred.
OS_ERROR_PARAMETER = 0x80, ///< parameter error: a mandatory parameter was missing or specified an incorrect object.
OS_ERROR_RESOURCE = 0x81, ///< resource not available: a specified resource was not available.
OS_ERROR_TIMEOUTRESOURCE = 0xC1, ///< resource not available within given time: a specified resource was not available within the timeout period.
OS_ERROR_ISR = 0x82, ///< not allowed in ISR context: the function cannot be called from interrupt service routines.
OS_ERROR_ISRRECURSIVE = 0x83, ///< function called multiple times from ISR with same object.
OS_ERROR_PRIORITY = 0x84, ///< system cannot determine priority or thread has illegal priority.
OS_ERROR_NOMEMORY = 0x85, ///< system is out of memory: it was impossible to allocate or reserve memory for the operation.
OS_ERROR_VALUE = 0x86, ///< value of a parameter is out of range.
OS_ERROR_OS = 0xFF, ///< unspecified RTOS error: run-time error but no other error message fits.
OS_STATUS_RESERVED = 0x7FFFFFFF ///< prevent from enum down-size compiler optimization.
} os_status;
os_status os_kernel_initialize (void);
os_status os_kernel_start(void);
os_status os_kernel_lock(void);
os_status os_kernel_unlock(void);
os_status os_delay(uint32_t ms);
uint32_t os_get_tick(void);
/************************************OS_EVENT************************************/
typedef struct os_mailq_cb *os_mail_qid;
typedef struct os_messageq_cb *os_message_qid;
typedef struct {
os_status status; ///< status code: event or error information
union {
uint32_t v; ///< message as 32-bit value
void *p; ///< message or mail as void pointer
int32_t signals; ///< signal flags
} value; ///< event value
union {
os_mail_qid mail_id; ///< mail id obtained by \ref osMailCreate
os_message_qid message_id; ///< message id obtained by \ref osMessageCreate
} def; ///< event definition
} os_event;
/************************************OS_THREAD************************************/
#ifndef FREERTOS
typedef enum {
OS_PRIORITY_IDLE = -3, ///< priority: idle (lowest)
OS_PRIORITY_LOW = -2, ///< priority: low
OS_PRIORITY_BELOWNORMAL = -1, ///< priority: below normal
OS_PRIORITY_NORMAL = 0, ///< priority: normal (default)
OS_PRIORITY_ABOVENORMAL = +1, ///< priority: above normal
OS_PRIORITY_HIGH = +2, ///< priority: high
OS_PRIORITY_REALTIME = +3, ///< priority: realtime (highest)
OS_PRIORITY_ERROR = 0x84 ///< system cannot determine priority or thread has illegal priority
} os_priority_t;
#else
typedef enum {
OS_PRIORITY_IDLE = 0, ///< priority: idle (lowest)
OS_PRIORITY_LOW = 1, ///< priority: low
OS_PRIORITY_BELOWNORMAL = 2, ///< priority: below normal
OS_PRIORITY_NORMAL = 3, ///< priority: normal (default)
OS_PRIORITY_ABOVENORMAL = 4, ///< priority: above normal
OS_PRIORITY_HIGH = 5, ///< priority: high
OS_PRIORITY_REALTIME = 6, ///< priority: realtime (highest)
OS_PRIORITY_ERROR = 0x84 ///< system cannot determine priority or thread has illegal priority
} os_priority_t;
#endif
typedef struct os_thread_cb *os_thread_id;
typedef void (*os_pthread) (void const *argument);
typedef struct {
os_pthread pthread; ///< start address of thread function
os_priority_t tpriority; ///< initial thread priority
uint32_t instances; ///< maximum number of instances of that thread function
uint32_t stacksize; ///< stack size requirements in bytes; 0 is default stack size
} os_thread_def_t;
#define os_thread(name) &os_thread_def_##name
#define os_thread_def(name, priority, instances, stacksz) \
const os_thread_def_t os_thread_def_##name = {(name), (priority), (instances), (stacksz)}
os_thread_id os_thread_create(const os_thread_def_t *thread_def, void *arg);
/************************************OS_TIMER************************************/
typedef struct os_timer_cb *os_timer_id;
typedef void (*os_ptimer) (void const *argument);
typedef struct
{
os_ptimer ptimer; ///< start address of a timer function
void *timer; ///< pointer to internal data
} os_timer_def_t;
typedef enum
{
OS_TIMER_ONCE = 0, ///< one-shot timer
OS_TIMER_PERIODIC = 1 ///< repeating timer
} os_timer_t;
#define os_timer(name) &os_timer_def_##name
#if (osCMSIS < 0x20000U)
#define os_timer_def(name, function) static uint8_t os_timer_cb_##name[40];\
static os_timer_def_t os_timer_def_##name = {(function), ((void *)os_timer_cb_##name)}
#else
#define os_timer_def(name, function) static const uint8_t os_timer_cb_##name[10];\
static const os_timer_def_t os_timer_def_##name = {(function), ((void *)os_timer_cb_##name)}
#endif
os_timer_id os_timer_create(const os_timer_def_t *timer_def, os_timer_t type, void *arg);
os_status os_timer_start(os_timer_id timer_id, uint32_t millisec);
os_status os_timer_stop(os_timer_id timer_id);
/************************************OS_MAIL************************************/
typedef struct os_mailq_cb *os_mail_qid;
#define os_mail_qdef(name, queue_sz, type) \
static const uint8_t os_mailq_q_##name[4 + (queue_sz)] = {0}; \
static const uint8_t os_mailq_m_##name[3 + ((sizeof(type) + 3) / 4) * (queue_sz)]; \
static void *os_mailq_p_##name[2] = {(os_mailq_q_##name), os_mailq_m_##name}; \
static const os_mailq_def_t os_mailq_def_##name = {(queue_sz), sizeof(type), (os_mailq_p_##name)} \
typedef struct os_mailq_def
{
uint16_t queue_sz; ///< number of elements in the queue
uint16_t item_sz; ///< size of an item
void *pool; ///< memory array for mail
} os_mailq_def_t;
#define os_mailq(name) &os_mailq_def_##name
os_mail_qid os_mail_create(const os_mailq_def_t *queue_def, os_thread_id thread_id);
void *os_mail_alloc(os_mail_qid queue_id, uint32_t millisec);
void *os_mail_clean_and_alloc(os_mail_qid queue_id, uint32_t millisec);
os_status os_mail_put(os_mail_qid queue_id, void *mail);
os_event os_mail_get(os_mail_qid queue_id, uint32_t millisec, void *arg);
os_status os_mail_free(os_mail_qid queue_id, void *mail);
/************************************OS_MSG_QUEUE************************************/
/// Message ID identifies the message queue (pointer to a message queue control block).
typedef struct os_messageq_cb *os_message_qid;
typedef struct os_messageq_def
{
uint32_t queue_sz; ///< number of elements in the queue
#if (osCMSIS < 0x20000U)
void *pool; ///< memory array for messages
#else
osMessageQueueAttr_t attr; ///< message queue attributes
#endif
} os_messageq_def_t;
#if (osCMSIS < 0x20000U)
#define os_message_qdef(name, queue_sz, type) \
static uint8_t os_messageq_q_##name[4 + (queue_sz)] = {0}; \
static const os_messageq_def_t os_messageq_def_##name = {(queue_sz), ((void *)os_messageq_q_##name)}
#else
#define os_message_qdef(name, queue_sz, type) \
static const os_messageq_def_t os_messageq_def_##name = {(queue_sz), { NULL, 0U, NULL, 0U, NULL, 0U }}
#endif
/// \brief Access a Message Queue Definition.
/// \param name name of the queue
#define os_messageq(name) &os_messageq_def_##name
os_message_qid os_message_create(const os_messageq_def_t *queue_def, os_thread_id thread_id);
os_status os_message_put(os_message_qid queue_id, uint32_t info, uint32_t millisec);
os_event os_message_get(os_message_qid queue_id, uint32_t millisec);
uint8_t os_message_get_space(os_message_qid queue_id);
uint8_t os_message_get_count(os_message_qid queue_id);
/************************************OS_POOL************************************/
/// Pool ID identifies the memory pool (pointer to a memory pool control block).
typedef struct os_pool_cb *os_pool_id;
typedef struct os_pool_deft
{
uint32_t pool_sz; ///< number of items (elements) in the pool
uint32_t item_sz; ///< size of an item
void *pool; ///< pointer to memory for pool
} os_pool_def_t;
#define os_pool_def(name, no, type) \
static const uint8_t os_pool_m_##name[3 + ((sizeof(type) + 3) / 4) * (no)]; \
static const os_pool_def_t os_pool_def_##name = {(no), sizeof(type), (void *)(os_pool_m_##name)}
#define os_pool(name) &os_pool_def_##name
os_pool_id os_pool_create(const os_pool_def_t *pool_def);
void *os_pool_alloc(os_pool_id pool_id);
void *os_pool_calloc(os_pool_id pool_id);
os_status os_pool_free(os_pool_id pool_id, void *block);
uint8_t os_pool_get_space(os_pool_id pool_id);
/************************************OS_SIGNAL************************************/
int32_t isr_signal_set(os_thread_id thread_id, int32_t signals);
int32_t os_signal_set(os_thread_id thread_id, int32_t signals);
int32_t os_signal_clear(os_thread_id thread_id, int32_t signals);
os_event os_signal_wait(int32_t signals, uint32_t millisec);
#ifdef FREERTOS
void get_task_info(void);
#endif