/* * Copyright (c) 2006-2025, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2018-04-12 misonyo the first version * 2019-04-04 misonyo fix some bugs * 2025-08-18 wdfk_prog fix osDelay bug */ #include #include "cmsis_rtthread.h" #include #include #include #define KERNEL_Id "RT-Thread" ///< Kernel identification string #define DEFAULT_STACK_SIZE 512 #define DEFAULT_TICK 5 #define WAITING_THREAD_FLAGS 0x08 #define MALLOC_CB 0x10 #define MALLOC_STACK 0x04 #define MALLOC_MEM 0x02 static osKernelState_t kernel_state = osKernelInactive; static void thread_cleanup(rt_thread_t thread) { thread_cb_t *thread_cb; thread_cb = (thread_cb_t *)(thread->user_data); /* clear cleanup function */ thread->cleanup = RT_NULL; if (thread_cb->flags & osThreadJoinable) { rt_sem_release(thread_cb->joinable_sem); } else { if (thread_cb->flags & MALLOC_STACK) rt_free(thread_cb->thread.stack_addr); if (thread_cb->flags & MALLOC_CB) rt_free(thread_cb); } } // ==== Kernel Management Functions ==== // ==== Helper functions ==== /// Block Kernel (disable: thread switching, time tick, post ISR processing). #ifdef SysTick static volatile uint8_t blocked; ///< Blocked static uint8_t pendSV; ///< Pending SV /// Get Pending SV (Service Call) Flag /// \return Pending SV Flag __STATIC_INLINE uint8_t GetPendSV (void) { return ((uint8_t)((SCB->ICSR & (SCB_ICSR_PENDSVSET_Msk)) >> 24)); } /// Clear Pending SV (Service Call) Flag __STATIC_INLINE void ClrPendSV (void) { SCB->ICSR = SCB_ICSR_PENDSVCLR_Msk; } /// Set Pending SV (Service Call) Flag __STATIC_INLINE void SetPendSV (void) { SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; } /// Block Kernel (disable: thread switching, time tick, post ISR processing). static void KernelBlock (void) { OS_Tick_Disable(); blocked = 1U; __DSB(); if (GetPendSV() != 0U) { ClrPendSV(); pendSV = 1U; } } /// Unblock Kernel static void KernelUnblock (void) { blocked = 0U; __DSB(); if (pendSV != 0U) { pendSV = 0U; SetPendSV(); } OS_Tick_Enable(); } #endif /// Initialize the RTOS Kernel. /// \return status code that indicates the execution status of the function. osStatus_t osKernelInitialize(void) { kernel_state = osKernelReady; return osOK; } /// Get RTOS Kernel Information. /// \param[out] version pointer to buffer for retrieving version information. /// \param[out] id_buf pointer to buffer for retrieving kernel identification string. /// \param[in] id_size size of buffer for kernel identification string. /// \return status code that indicates the execution status of the function. osStatus_t osKernelGetInfo(osVersion_t *version, char *id_buf, uint32_t id_size) { if ((RT_NULL == version) || (RT_NULL == id_buf) || id_size < sizeof(KERNEL_Id)) return osErrorParameter; version->api = KERNEL_VERSION; version->kernel = KERNEL_VERSION; id_size = sizeof(KERNEL_Id); rt_strncpy(id_buf, KERNEL_Id, id_size); return osOK; } /// Get the current RTOS Kernel state. /// \return current RTOS Kernel state. osKernelState_t osKernelGetState(void) { return kernel_state; } /// Start the RTOS Kernel scheduler. /// \return status code that indicates the execution status of the function. osStatus_t osKernelStart(void) { osStatus_t state; if (osKernelReady == kernel_state) { kernel_state = osKernelRunning; state = osOK; } else { state = osError; } return state; } /// Lock the RTOS Kernel scheduler. /// \return previous lock state (1 - locked, 0 - not locked, error code if negative). int32_t osKernelLock(void) { rt_uint16_t level; level = rt_critical_level(); rt_enter_critical(); kernel_state = osKernelLocked; if (level) { return 1; } else { return 0; } } /// Unlock the RTOS Kernel scheduler. /// \return previous lock state (1 - locked, 0 - not locked, error code if negative). int32_t osKernelUnlock(void) { rt_uint16_t level; level = rt_critical_level(); if (0U == level) { return 0; } else { rt_exit_critical(); if (1u == level) kernel_state = osKernelRunning; return 1; } } /// Restore the RTOS Kernel scheduler lock state. /// \param[in] lock lock state obtained by \ref osKernelLock or \ref osKernelUnlock. /// \return new lock state (1 - locked, 0 - not locked, error code if negative). int32_t osKernelRestoreLock(int32_t lock) { if (1u == lock) { osKernelLock(); return 1; } else { osKernelUnlock(); return 0; } } /// Get the RTOS kernel tick count. /// \return RTOS kernel current tick count. uint32_t osKernelGetTickCount(void) { return (uint32_t)rt_tick_get(); } /// Get the RTOS kernel tick frequency. /// \return frequency of the kernel tick. uint32_t osKernelGetTickFreq(void) { return RT_TICK_PER_SECOND; } /// The function returns the current RTOS kernel system timer as a 32-bit value. /// \return RTOS kernel current system timer count as 32-bit value #ifdef SysTick uint32_t osKernelGetSysTimerCount(void) { uint32_t irqmask ; rt_tick_t ticks; uint32_t val; irqmask = rt_hw_interrupt_disable(); ticks = rt_tick_get(); val = OS_Tick_GetCount(); if (OS_Tick_GetOverflow() != 0U) { val = OS_Tick_GetCount(); ticks++; } val += ticks * OS_Tick_GetInterval(); rt_hw_interrupt_enable(irqmask); return (val); } #endif /*SysTick*/ /// Get the RTOS kernel system timer frequency. /// \return frequency of the system timer. uint32_t osKernelGetSysTimerFreq(void) { return RT_TICK_PER_SECOND; } /// Suspend the RTOS Kernel scheduler. /// \return time in ticks, for how long the system can sleep or power-down. #ifdef SysTick uint32_t osKernelSuspend (void) { rt_thread_t thread; rt_timer_t timer; struct rt_object_information *info_thread; struct rt_object_information *info_timer; struct rt_list_node *node; rt_uint8_t timer_index = 0; rt_tick_t min_tick = 0; rt_tick_t cur_tick = 0; rt_tick_t temp_tick = 0; if (kernel_state != osKernelRunning) { return 0U; } info_thread = rt_object_get_information(RT_Object_Class_Thread); info_timer = rt_object_get_information(RT_Object_Class_Timer); KernelBlock(); min_tick = osWaitForever; cur_tick = rt_tick_get(); /*check thread delay list*/ if (info_thread != NULL) { for (node = info_thread->object_list.next; node != &(info_thread->object_list); node = node->next) { thread = thread_rt_list_entry(node, rt_thread); if (thread->thread_timer.parent.flag & RT_TIMER_FLAG_ACTIVATED) { temp_tick = thread->thread_timer.timeout_tick - cur_tick; if (temp_tick < min_tick) { min_tick = temp_tick; } } } } /*check active timer list*/ if (info_timer != NULL) { for (node = info_timer->object_list.next; node != &(info_timer->object_list); node = node->next) { timer = rt_list_entry(node, struct rt_timer, row[timer_index++]); if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED) { temp_tick = timer->timeout_tick - cur_tick; if (temp_tick < min_tick) { min_tick = temp_tick; } } } } if (osWaitForever == min_tick) min_tick = 0U; kernel_state = osKernelSuspended; return (min_tick); } #endif /* SysTick */ /// Resume the RTOS Kernel scheduler. /// \param[in] sleep_ticks time in ticks for how long the system was in sleep or power-down mode. #ifdef SysTick void osKernelResume (uint32_t sleep_ticks) { rt_tick_t delay_tick = 0; if (kernel_state != osKernelSuspended) { return; } delay_tick = (rt_tick_t)sleep_ticks; rt_enter_critical(); while(delay_tick > 0) { rt_tick_increase(); /*Process Thread Delay list and Process Active Timer list*/ delay_tick --; } rt_exit_critical(); kernel_state = osKernelRunning; KernelUnblock(); return; } #endif // ==== Thread Management Functions ==== /// Create a thread and add it to Active Threads. /// \param[in] func thread function. /// \param[in] argument pointer that is passed to the thread function as start argument. /// \param[in] attr thread attributes; NULL: default values. /// \return thread ID for reference by other functions or NULL in case of error. osThreadId_t osThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr) { void *stack; rt_uint8_t rtt_prio; rt_uint32_t stack_size; thread_cb_t *thread_cb; char name[RT_NAME_MAX]; static rt_uint16_t thread_number = 1U; /* Check parameters */ if (RT_NULL == func) { return RT_NULL; } if ((RT_NULL == attr) || (RT_NULL == attr->cb_mem)) { thread_cb = rt_malloc(sizeof(thread_cb_t)); if (RT_NULL == thread_cb) return RT_NULL; rt_memset(thread_cb, 0, sizeof(thread_cb_t)); thread_cb->flags |= MALLOC_CB; } else { if (attr->cb_size >= sizeof(thread_cb_t)) { thread_cb = attr->cb_mem; thread_cb->flags = 0; } else return RT_NULL; } if ((RT_NULL == attr) || (RT_NULL == attr->name)) rt_snprintf(name, sizeof(name), "th%02d", thread_number ++); else rt_snprintf(name, sizeof(name), "%s", attr->name); if ((RT_NULL == attr) || (osPriorityNone == attr->priority)) { thread_cb->prio = osPriorityNormal; } else { if ((attr->priority < osPriorityIdle) || (attr->priority > osPriorityISR)) return RT_NULL; thread_cb->prio = attr->priority; } if ((RT_NULL == attr) || (0U == attr->stack_size)) stack_size = DEFAULT_STACK_SIZE; else stack_size = attr->stack_size; if ((RT_NULL == attr) || (RT_NULL == attr->stack_mem)) { stack = rt_malloc(stack_size); if (RT_NULL == stack) { if (thread_cb->flags & MALLOC_CB) rt_free(thread_cb); return RT_NULL; } thread_cb->flags |= MALLOC_STACK; } else { stack = (void *)(attr->stack_mem); } if ((RT_NULL != attr) && (0 != attr->attr_bits)) thread_cb->flags |= attr->attr_bits; rtt_prio = (osPriorityISR - thread_cb->prio) * RT_THREAD_PRIORITY_MAX / osPriorityISR; rt_thread_init(&(thread_cb->thread), name, func, argument, stack, stack_size, rtt_prio, DEFAULT_TICK); if (thread_cb->flags & osThreadJoinable) { thread_cb->joinable_sem = rt_sem_create(name, 0, RT_IPC_FLAG_FIFO); if (RT_NULL == thread_cb->joinable_sem) { if (thread_cb->flags & MALLOC_CB) rt_free(thread_cb); if (thread_cb->flags & MALLOC_STACK) rt_free(stack); return RT_NULL; } } else thread_cb->joinable_sem = RT_NULL; thread_cb->thread.cleanup = thread_cleanup; thread_cb->thread.user_data = (rt_uint32_t)thread_cb; rt_thread_startup(&(thread_cb->thread)); return thread_cb; } /// Get name of a thread. /// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. /// \return name as NULL terminated string. const char *osThreadGetName(osThreadId_t thread_id) { thread_cb_t *thread_cb = (thread_cb_t *)thread_id; /* Check parameters */ if ((RT_NULL == thread_cb) || (rt_object_get_type((rt_object_t)(&thread_cb->thread)) != RT_Object_Class_Thread)) { return RT_NULL; } return THREAD_NAME(thread_cb); } /// Return the thread ID of the current running thread. /// \return thread ID for reference by other functions or NULL in case of error. osThreadId_t osThreadGetId(void) { rt_thread_t thread; thread = rt_thread_self(); return (osThreadId_t)(thread->user_data); } /// Get current thread state of a thread. /// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. /// \return current thread state of the specified thread. osThreadState_t osThreadGetState(osThreadId_t thread_id) { osThreadState_t state; thread_cb_t *thread_cb = (thread_cb_t *)thread_id; /* Check parameters */ if ((RT_NULL == thread_cb) || (rt_object_get_type((rt_object_t)(&thread_cb->thread)) != RT_Object_Class_Thread)) { return osThreadError; } switch (CMSIS_RT_SCHED_CTX(thread_cb->thread).stat) { case RT_THREAD_INIT: state = osThreadInactive; break; case RT_THREAD_READY: state = osThreadReady; break; case RT_THREAD_SUSPEND: state = osThreadBlocked; break; case RT_THREAD_RUNNING: state = osThreadRunning; break; case RT_THREAD_CLOSE: state = osThreadTerminated; break; default: state = osThreadError; break; } return state; } /// Get stack size of a thread. /// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. /// \return stack size in bytes. uint32_t osThreadGetStackSize(osThreadId_t thread_id) { thread_cb_t *thread_cb = (thread_cb_t *)thread_id; /* Check parameters */ if ((RT_NULL == thread_cb) || (rt_object_get_type((rt_object_t)(&thread_cb->thread)) != RT_Object_Class_Thread)) { return 0U; } return ((uint32_t)thread_cb->thread.stack_size); } /// Get available stack space of a thread based on stack watermark recording during execution. /// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. /// \return remaining stack space in bytes. uint32_t osThreadGetStackSpace(osThreadId_t thread_id) { rt_uint8_t *ptr; thread_cb_t *thread_cb = (thread_cb_t *)thread_id; /* Check parameters */ if ((RT_NULL == thread_cb) || (rt_object_get_type((rt_object_t)(&thread_cb->thread)) != RT_Object_Class_Thread)) { return 0U; } ptr = (rt_uint8_t *)thread_cb->thread.stack_addr; while (*ptr == '#')ptr ++; return (ptr - (rt_uint8_t *)thread_cb->thread.stack_addr); } /// Change priority of a thread. /// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. /// \param[in] priority new priority value for the thread function. /// \return status code that indicates the execution status of the function. osStatus_t osThreadSetPriority(osThreadId_t thread_id, osPriority_t priority) { rt_uint8_t rt_priority; thread_cb_t *thread_cb = (thread_cb_t *)thread_id; // Check parameters if ((RT_NULL == thread_cb) || (priority < osPriorityIdle) || (priority > osPriorityISR)) { return osErrorParameter; } thread_cb->prio = priority; rt_priority = (osPriorityISR - thread_cb->prio) * RT_THREAD_PRIORITY_MAX / osPriorityISR; rt_thread_control(&(thread_cb->thread), RT_THREAD_CTRL_CHANGE_PRIORITY, &rt_priority); return osOK; } /// Get current priority of a thread. /// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. /// \return current priority value of the specified thread. osPriority_t osThreadGetPriority(osThreadId_t thread_id) { thread_cb_t *thread_cb = (thread_cb_t *)thread_id; /* Check parameters */ if ((RT_NULL == thread_cb) || (rt_object_get_type((rt_object_t)(&thread_cb->thread)) != RT_Object_Class_Thread)) { return osPriorityError; } return (osPriority_t)thread_cb->prio; } /// Pass control to next thread that is in state \b READY. /// \return status code that indicates the execution status of the function. osStatus_t osThreadYield(void) { rt_thread_yield(); return osOK; } /// Suspend execution of a thread. /// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. /// \return status code that indicates the execution status of the function. osStatus_t osThreadSuspend(osThreadId_t thread_id) { rt_err_t result; thread_cb_t *thread_cb = (thread_cb_t *)thread_id; /* Check parameters */ if (RT_NULL == thread_cb) { return osErrorParameter; } result = rt_thread_suspend(&(thread_cb->thread)); if (RT_EOK == result) return osOK; else return osError; } /// Resume execution of a thread. /// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. /// \return status code that indicates the execution status of the function. osStatus_t osThreadResume(osThreadId_t thread_id) { rt_err_t result; thread_cb_t *thread_cb = (thread_cb_t *)thread_id; /* Check parameters */ if (RT_NULL == thread_cb) { return osErrorParameter; } result = rt_thread_resume(&(thread_cb->thread)); if (RT_EOK == result) return osOK; else return osError; } /// Detach a thread (thread storage can be reclaimed when thread terminates). /// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. /// \return status code that indicates the execution status of the function. osStatus_t osThreadDetach(osThreadId_t thread_id) { thread_cb_t *thread_cb = (thread_cb_t *)thread_id; /* Check parameters */ if ((RT_NULL == thread_cb) || (rt_object_get_type((rt_object_t)(&thread_cb->thread)) != RT_Object_Class_Thread)) { return osErrorParameter; } /* Check object attributes */ /* if ((thread_cb->flags & osThreadJoinable) == 0) { return osErrorResource; } */ if ((CMSIS_RT_SCHED_CTX(thread_cb->thread).stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE) { rt_thread_detach(&(thread_cb->thread)); if (thread_cb->flags & osThreadJoinable) rt_sem_delete(thread_cb->joinable_sem); if (thread_cb->flags & MALLOC_STACK) rt_free(thread_cb->thread.stack_addr); if (thread_cb->flags & MALLOC_CB) rt_free(thread_cb); } else { rt_enter_critical(); /* change to detach state */ thread_cb->flags &= ~osThreadJoinable; /* delete joinable semaphore */ if (RT_NULL != thread_cb->joinable_sem) { rt_sem_delete(thread_cb->joinable_sem); thread_cb->joinable_sem = RT_NULL; } /* detach thread object */ rt_thread_detach(&thread_cb->thread); rt_exit_critical(); } return osOK; } /// Wait for specified thread to terminate. /// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. /// \return status code that indicates the execution status of the function. osStatus_t osThreadJoin(osThreadId_t thread_id) { rt_err_t result; thread_cb_t *thread_cb = (thread_cb_t *)thread_id; /* Check parameters */ if (RT_NULL == thread_cb) { return osErrorParameter; } if (((&thread_cb->thread) == rt_thread_self()) || (0 == (thread_cb->flags & osThreadJoinable))) { /* join self or join a detached thread*/ return osErrorResource; } result = rt_sem_take(thread_cb->joinable_sem, RT_WAITING_FOREVER); if (RT_EOK == result) { /* release resource */ if (thread_cb->flags & osThreadJoinable) rt_sem_delete(thread_cb->joinable_sem); if (thread_cb->flags & MALLOC_STACK) rt_free(thread_cb->thread.stack_addr); if (thread_cb->flags & MALLOC_CB) rt_free(thread_cb); return osOK; } else if (-RT_ETIMEOUT == result) { return osErrorTimeout; } else { return osError; } } /// Terminate execution of current running thread. __NO_RETURN void osThreadExit(void) { rt_thread_t self = rt_thread_self(); rt_thread_control(self, RT_THREAD_CTRL_CLOSE, RT_NULL); RT_ASSERT(0); while(1); } /// Terminate execution of a thread. /// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. /// \return status code that indicates the execution status of the function. osStatus_t osThreadTerminate(osThreadId_t thread_id) { thread_cb_t *thread_cb; thread_cb = (thread_cb_t *)(rt_thread_self()->user_data); /* Check parameters */ if (RT_NULL == thread_cb) { return osErrorParameter; } rt_thread_detach(&(thread_cb->thread)); rt_schedule(); return osOK; } /// Get number of active threads. /// \return number of active threads. uint32_t osThreadGetCount(void) { rt_uint32_t thread_count = 0U; struct rt_object_information *info; info = rt_object_get_information(RT_Object_Class_Thread); rt_enter_critical(); thread_count = rt_list_len(&(info->object_list)); rt_exit_critical(); return thread_count; } /// Enumerate active threads. /// \param[out] thread_array pointer to array for retrieving thread IDs. /// \param[in] array_items maximum number of items in array for retrieving thread IDs. /// \return number of enumerated threads. uint32_t osThreadEnumerate(osThreadId_t *thread_array, uint32_t array_items) { rt_uint32_t thread_count = 0U; rt_thread_t thread; struct rt_object_information *info; struct rt_list_node *node; /* Check parameters */ if ((RT_NULL == thread_array) || (0U == array_items)) { return 0U; } info = rt_object_get_information(RT_Object_Class_Thread); rt_enter_critical(); for (node = info->object_list.next; node != &(info->object_list); node = node->next) { thread = thread_rt_list_entry(node, rt_thread); thread_array[thread_count] = (osThreadId_t)thread; thread_count++; if (thread_count >= array_items) break; } rt_exit_critical(); return thread_count; } // ==== Thread Flags Functions ==== /// Set the specified Thread Flags of a thread. /// \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId. /// \param[in] flags specifies the flags of the thread that shall be set. /// \return thread flags after setting or error code if highest bit set. uint32_t osThreadFlagsSet(osThreadId_t thread_id, uint32_t flags) { register rt_base_t status; register rt_ubase_t level; rt_bool_t need_schedule = RT_FALSE; thread_cb_t *thread_cb; rt_uint32_t return_value; thread_cb = (thread_cb_t *)(thread_id); /* Check parameters */ if ((RT_NULL == thread_cb) || (rt_object_get_type((rt_object_t)(&thread_cb->thread)) != RT_Object_Class_Thread)) { return osFlagsErrorParameter; } level = rt_hw_interrupt_disable(); thread_cb->flag_set |= flags; return_value = thread_cb->flag_set; /* Check if Thread is waiting for Thread Flags */ if (thread_cb->thread.event_info & WAITING_THREAD_FLAGS) { status = -RT_ERROR; if (thread_cb->thread.event_info & osFlagsWaitAll) { if ((thread_cb->thread.event_set & thread_cb->flag_set) == thread_cb->thread.event_set) { /* received an AND event */ status = RT_EOK; } } else { if (thread_cb->thread.event_set & thread_cb->flag_set) { /* save recieved event set */ thread_cb->thread.event_set &= thread_cb->flag_set; /* received an OR event */ status = RT_EOK; } } /* condition is satisfied, resume thread */ if (RT_EOK == status) { thread_cb->thread.event_info &= ~WAITING_THREAD_FLAGS; /* clear event */ if (!(thread_cb->thread.event_info & osFlagsNoClear)) thread_cb->flag_set &= ~thread_cb->thread.event_set; /* resume thread, and thread list breaks out */ rt_thread_resume(&(thread_cb->thread)); need_schedule = RT_TRUE; } } rt_hw_interrupt_enable(level); if (need_schedule == RT_TRUE) rt_schedule(); return return_value; } /// Clear the specified Thread Flags of current running thread. /// \param[in] flags specifies the flags of the thread that shall be cleared. /// \return thread flags before clearing or error code if highest bit set. uint32_t osThreadFlagsClear(uint32_t flags) { rt_thread_t thread = rt_thread_self(); thread_cb_t *thread_cb; rt_uint32_t flag; /* Check parameters */ if (RT_NULL == thread) { return osFlagsErrorParameter; } thread_cb = (thread_cb_t *)(thread->user_data); rt_enter_critical(); flag = thread_cb->flag_set; thread_cb->flag_set &= ~flags; rt_exit_critical(); return flag; } /// Get the current Thread Flags of current running thread. /// \return current thread flags. uint32_t osThreadFlagsGet(void) { rt_thread_t thread = rt_thread_self(); thread_cb_t *thread_cb; /* Check parameters */ if (RT_NULL == thread) { return osFlagsErrorParameter; } thread_cb = (thread_cb_t *)(thread->user_data); return thread_cb->flag_set; } /// Wait for one or more Thread Flags of the current running thread to become signaled. /// \param[in] flags specifies the flags to wait for. /// \param[in] options specifies flags options (osFlagsXxxx). /// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out. /// \return thread flags before clearing or error code if highest bit set. uint32_t osThreadFlagsWait(uint32_t flags, uint32_t options, uint32_t timeout) { rt_uint32_t return_value; register rt_ubase_t level; register rt_base_t status = -RT_ERROR; rt_thread_t thread = rt_thread_self(); thread_cb_t *thread_cb; /* Check parameters */ if (RT_NULL == thread) { return osFlagsErrorParameter; } thread->error = RT_EOK; thread_cb = (thread_cb_t *)(thread->user_data); level = rt_hw_interrupt_disable(); if (options & osFlagsWaitAll) { if ((thread_cb->flag_set & flags) == flags) status = RT_EOK; } else { if (thread_cb->flag_set & flags) status = RT_EOK; } if (RT_EOK == status) { return_value = thread_cb->flag_set & flags; if (!(options & osFlagsNoClear)) thread_cb->flag_set &= ~flags; } else if (0U == timeout) { rt_hw_interrupt_enable(level); return osFlagsErrorResource; } else { thread->event_set = flags; thread->event_info = options | WAITING_THREAD_FLAGS; rt_thread_suspend(thread); /* if there is a waiting timeout, active thread timer */ if ((timeout > 0U) && (timeout != osWaitForever)) { /* reset the timeout of thread timer and start it */ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &timeout); rt_timer_start(&(thread->thread_timer)); } rt_hw_interrupt_enable(level); rt_schedule(); if (thread->error != RT_EOK) { return thread->error; } level = rt_hw_interrupt_disable(); return_value = thread->event_set; } rt_hw_interrupt_enable(level); return return_value; } // ==== Generic Wait Functions ==== /// Wait for Timeout (Time Delay). /// \param[in] ticks \ref CMSIS_RTOS_TimeOutValue "time ticks" value /// \return status code that indicates the execution status of the function. osStatus_t osDelay(uint32_t ticks) { if (rt_interrupt_get_nest() != 0) { return osErrorISR; } else { if(rt_thread_delay(ticks) != RT_EOK) { return osError; } else { return osOK; } } } /// Wait until specified time. /// \param[in] ticks absolute time in ticks /// \return status code that indicates the execution status of the function. osStatus_t osDelayUntil(uint32_t ticks) { uint64_t cur_ticks; cur_ticks = rt_tick_get(); if (ticks == cur_ticks) { } else if (ticks > cur_ticks) { rt_thread_delay(ticks - cur_ticks); } else { rt_thread_delay(((rt_uint32_t) - 1) - cur_ticks + ticks); } return osOK; } // ==== Timer Management Functions ==== /// Create and Initialize a timer. /// \param[in] func start address of a timer call back function. /// \param[in] type osTimerOnce for one-shot or osTimerPeriodic for periodic behavior. /// \param[in] argument argument to the timer call back function. /// \param[in] attr timer attributes; NULL: default values. /// \return timer ID for reference by other functions or NULL in case of error. osTimerId_t osTimerNew(osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr) { timer_cb_t *timer_cb; char name[RT_NAME_MAX]; static rt_uint16_t timer_number = 0U; rt_uint8_t flag = RT_TIMER_FLAG_SOFT_TIMER; /* Check parameters */ if ((RT_NULL == func) || ((type != osTimerOnce) && (type != osTimerPeriodic))) { return RT_NULL; } /* RT-Thread object's name can't be NULL */ if ((RT_NULL == attr) || (RT_NULL == attr->name)) rt_snprintf(name, sizeof(name), "timer%02d", timer_number++); else rt_snprintf(name, sizeof(name), "%s", attr->name); if ((RT_NULL == attr) || (RT_NULL == attr->cb_mem)) { timer_cb = rt_malloc(sizeof(timer_cb_t)); if (RT_NULL == timer_cb) return RT_NULL; rt_memset(timer_cb, 0, sizeof(timer_cb_t)); timer_cb->flags |= MALLOC_CB; } else { if (attr->cb_size >= sizeof(timer_cb_t)) { timer_cb = attr->cb_mem; timer_cb->flags = 0; } else return RT_NULL; } if (osTimerPeriodic == type) { flag |= RT_TIMER_FLAG_PERIODIC; } rt_timer_init(&(timer_cb->timer), name, func, argument, 0, flag); return timer_cb; } /// Get name of a timer. /// \param[in] timer_id timer ID obtained by \ref osTimerNew. /// \return name as NULL terminated string. const char *osTimerGetName(osTimerId_t timer_id) { timer_cb_t *timer_cb; timer_cb = (timer_cb_t *)timer_id; /* Check parameters */ if ((RT_NULL == timer_cb) || (rt_object_get_type(&timer_cb->timer.parent) != RT_Object_Class_Timer)) { return RT_NULL; } return timer_cb->timer.parent.name; } /// Start or restart a timer. /// \param[in] timer_id timer ID obtained by \ref osTimerNew. /// \param[in] ticks \ref CMSIS_RTOS_TimeOutValue "time ticks" value of the timer. /// \return status code that indicates the execution status of the function. osStatus_t osTimerStart(osTimerId_t timer_id, uint32_t ticks) { rt_err_t result; timer_cb_t *timer_cb; timer_cb = (timer_cb_t *)timer_id; /* Check parameters */ if ((RT_NULL == timer_cb) || (ticks == 0)) { return osErrorParameter; } rt_timer_control(&(timer_cb->timer), RT_TIMER_CTRL_SET_TIME, &ticks); result = rt_timer_start(&(timer_cb->timer)); if (RT_EOK == result) return osOK; else return osError; } /// Stop a timer. /// \param[in] timer_id timer ID obtained by \ref osTimerNew. /// \return status code that indicates the execution status of the function. osStatus_t osTimerStop(osTimerId_t timer_id) { rt_err_t result; timer_cb_t *timer_cb; timer_cb = (timer_cb_t *)timer_id; /* Check parameters */ if (RT_NULL == timer_cb) { return osErrorParameter; } result = rt_timer_stop(&(timer_cb->timer)); if (RT_EOK == result) return osOK; else return osError; } /// Check if a timer is running. /// \param[in] timer_id timer ID obtained by \ref osTimerNew. /// \return 0 not running, 1 running. uint32_t osTimerIsRunning(osTimerId_t timer_id) { timer_cb_t *timer_cb; timer_cb = (timer_cb_t *)timer_id; /* Check parameters */ if ((RT_NULL == timer_cb) || (rt_object_get_type(&timer_cb->timer.parent) != RT_Object_Class_Timer)) { return 0U; } if ((timer_cb->timer.parent.flag & RT_TIMER_FLAG_ACTIVATED) == 1u) { return 1; } else return 0U; } /// Delete a timer. /// \param[in] timer_id timer ID obtained by \ref osTimerNew. /// \return status code that indicates the execution status of the function. osStatus_t osTimerDelete(osTimerId_t timer_id) { timer_cb_t *timer_cb; timer_cb = (timer_cb_t *)timer_id; /* Check parameters */ if (RT_NULL == timer_cb) { return osErrorParameter; } rt_timer_detach(&(timer_cb->timer)); if (timer_cb->flags & MALLOC_CB) rt_free(timer_cb); return osOK; } #ifdef RT_USING_EVENT // ==== Event Flags Management Functions ==== /// Create and Initialize an Event Flags object. /// \param[in] attr event flags attributes; NULL: default values. /// \return event flags ID for reference by other functions or NULL in case of error. osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr) { char name[RT_NAME_MAX]; event_cb_t *event_cb; static rt_uint16_t event_number = 0U; if ((RT_NULL == attr) || (RT_NULL == attr->name)) { rt_snprintf(name, sizeof(name), "event%02d", event_number++); } else rt_snprintf(name, sizeof(name), "%s", attr->name); if ((RT_NULL == attr) || (RT_NULL == attr->cb_mem)) { event_cb = rt_malloc(sizeof(event_cb_t)); if (RT_NULL == event_cb) return RT_NULL; rt_memset(event_cb, 0, sizeof(event_cb_t)); event_cb->flags |= MALLOC_CB; } else { if (attr->cb_size >= sizeof(event_cb_t)) { event_cb = attr->cb_mem; event_cb->flags = 0; } else return RT_NULL; } rt_event_init(&(event_cb->event), name, RT_IPC_FLAG_FIFO); return event_cb; } /// Get name of an Event Flags object. /// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. /// \return name as NULL terminated string. const char *osEventFlagsGetName(osEventFlagsId_t ef_id) { event_cb_t *event_cb = (event_cb_t *)ef_id; /* Check parameters */ if ((RT_NULL == event_cb) || (rt_object_get_type(&event_cb->event.parent.parent) != RT_Object_Class_Event)) { return RT_NULL; } return event_cb->event.parent.parent.name; } /// Set the specified Event Flags. /// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. /// \param[in] flags specifies the flags that shall be set. /// \return event flags after setting or error code if highest bit set. uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags) { rt_err_t result; rt_uint32_t set_flags; event_cb_t *event_cb = (event_cb_t *)ef_id; /* Check parameters */ if ((RT_NULL == event_cb) || (rt_object_get_type(&event_cb->event.parent.parent) != RT_Object_Class_Event)) { return ((uint32_t)osFlagsErrorParameter); } set_flags = event_cb->event.set |= flags; result = rt_event_send(&(event_cb->event), flags); if (RT_EOK == result) return set_flags; else return osFlagsError; } /// Clear the specified Event Flags. /// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. /// \param[in] flags specifies the flags that shall be cleared. /// \return event flags before clearing or error code if highest bit set. uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags) { rt_uint32_t set_flags; register rt_ubase_t level; event_cb_t *event_cb = (event_cb_t *)ef_id; /* Check parameters */ if ((RT_NULL == event_cb) || (rt_object_get_type(&event_cb->event.parent.parent) != RT_Object_Class_Event)) { return ((uint32_t)osFlagsErrorParameter); } set_flags = event_cb->event.set; level = rt_hw_interrupt_disable(); event_cb->event.set &= ~flags; rt_hw_interrupt_enable(level); return set_flags; } /// Get the current Event Flags. /// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. /// \return current event flags. uint32_t osEventFlagsGet(osEventFlagsId_t ef_id) { event_cb_t *event_cb = (event_cb_t *)ef_id; /* Check parameters */ if ((RT_NULL == event_cb) || (rt_object_get_type(&event_cb->event.parent.parent) != RT_Object_Class_Event)) { return 0U; } return event_cb->event.set; } /// Wait for one or more Event Flags to become signaled. /// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. /// \param[in] flags specifies the flags to wait for. /// \param[in] options specifies flags options (osFlagsXxxx). /// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out. /// \return event flags before clearing or error code if highest bit set. uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout) { rt_err_t result; rt_uint32_t rt_recv; rt_uint8_t rt_options = 0U; event_cb_t *event_cb = (event_cb_t *)ef_id; /* Check parameters */ if (RT_NULL == event_cb) { return ((uint32_t)osFlagsErrorParameter); } if (options & osFlagsWaitAll) { rt_options |= RT_EVENT_FLAG_AND; } else { rt_options |= RT_EVENT_FLAG_OR; } if (!(options & osFlagsNoClear)) { rt_options |= RT_EVENT_FLAG_CLEAR; } if(timeout == osWaitForever) { timeout = RT_WAITING_FOREVER; } result = rt_event_recv(&(event_cb->event), flags, (rt_uint8_t)rt_options, timeout, &rt_recv); if (RT_EOK == result) return rt_recv; else if (-RT_ETIMEOUT == result) { if (0U == timeout) return osFlagsErrorResource; else return osFlagsErrorTimeout; } else return osFlagsErrorUnknown; } /// Delete an Event Flags object. /// \param[in] ef_id event flags ID obtained by \ref osEventFlagsNew. /// \return status code that indicates the execution status of the function. osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id) { event_cb_t *event_cb = (event_cb_t *)ef_id; /* Check parameters */ if (RT_NULL == event_cb) { return osErrorParameter; } rt_event_detach(&(event_cb->event)); if (event_cb->flags & MALLOC_CB) rt_free(event_cb); return osOK; } #endif #ifdef RT_USING_MUTEX // ==== Mutex Management Functions ==== /// Create and Initialize a Mutex object. /// \param[in] attr mutex attributes; NULL: default values. /// \return mutex ID for reference by other functions or NULL in case of error. osMutexId_t osMutexNew(const osMutexAttr_t *attr) { char name[RT_NAME_MAX]; mutex_cb_t *mutex_cb; static rt_uint16_t mutex_number = 0U; if ((RT_NULL == attr) || (RT_NULL == attr->name)) { rt_snprintf(name, sizeof(name), "mutex%02d", mutex_number++); } else rt_snprintf(name, sizeof(name), "%s", attr->name); if ((RT_NULL == attr) || (RT_NULL == attr->cb_mem)) { mutex_cb = rt_malloc(sizeof(mutex_cb_t)); if (RT_NULL == mutex_cb) return RT_NULL; rt_memset(mutex_cb, 0, sizeof(mutex_cb_t)); mutex_cb->flags |= MALLOC_CB; } else { if (attr->cb_size >= sizeof(mutex_cb_t)) { mutex_cb = attr->cb_mem; mutex_cb->flags = 0; } else return RT_NULL; } if ((RT_NULL == attr) || (0 == attr->attr_bits)) { mutex_cb->flags |= osMutexRecursive; } else mutex_cb->flags |= attr->attr_bits; rt_mutex_init(&(mutex_cb->mutex), name, RT_IPC_FLAG_FIFO); return mutex_cb; } /// Get name of a Mutex object. /// \param[in] mutex_id mutex ID obtained by \ref osMutexNew. /// \return name as NULL terminated string. const char *osMutexGetName(osMutexId_t mutex_id) { mutex_cb_t *mutex_cb = (mutex_cb_t *)mutex_id; /* Check parameters */ if ((RT_NULL == mutex_cb) || (rt_object_get_type(&mutex_cb->mutex.parent.parent) != RT_Object_Class_Mutex)) { return RT_NULL; } return mutex_cb->mutex.parent.parent.name; } /// Acquire a Mutex or timeout if it is locked. /// \param[in] mutex_id mutex ID obtained by \ref osMutexNew. /// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out. /// \return status code that indicates the execution status of the function. osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout) { rt_err_t result; mutex_cb_t *mutex_cb = (mutex_cb_t *)mutex_id; /* Check parameters */ if (RT_NULL == mutex_cb) { return osErrorParameter; } rt_enter_critical(); if ((mutex_cb->mutex.owner == rt_thread_self()) && !(mutex_cb->flags & osMutexRecursive)) { rt_exit_critical(); return osError; } rt_exit_critical(); if(timeout == osWaitForever) { timeout = RT_WAITING_FOREVER; } result = rt_mutex_take(&(mutex_cb->mutex), timeout); if (RT_EOK == result) return osOK; else if (-RT_ETIMEOUT == result) { if (0U == timeout) return osErrorResource; else return osErrorTimeout; } else return osError; } /// Release a Mutex that was acquired by \ref osMutexAcquire. /// \param[in] mutex_id mutex ID obtained by \ref osMutexNew. /// \return status code that indicates the execution status of the function. osStatus_t osMutexRelease(osMutexId_t mutex_id) { rt_err_t result; mutex_cb_t *mutex_cb = (mutex_cb_t *)mutex_id; /* Check parameters */ if (RT_NULL == mutex_cb) { return osErrorParameter; } result = rt_mutex_release(&(mutex_cb->mutex)); if (RT_EOK == result) return osOK; else return osErrorResource; } /// Get Thread which owns a Mutex object. /// \param[in] mutex_id mutex ID obtained by \ref osMutexNew. /// \return thread ID of owner thread or NULL when mutex was not acquired. osThreadId_t osMutexGetOwner(osMutexId_t mutex_id) { mutex_cb_t *mutex_cb = (mutex_cb_t *)mutex_id; /* Check parameters */ if ((RT_NULL == mutex_cb) || (rt_object_get_type(&mutex_cb->mutex.parent.parent) != RT_Object_Class_Mutex)) { return RT_NULL; } return mutex_cb->mutex.owner; } /// Delete a Mutex object. /// \param[in] mutex_id mutex ID obtained by \ref osMutexNew. /// \return status code that indicates the execution status of the function. osStatus_t osMutexDelete(osMutexId_t mutex_id) { mutex_cb_t *mutex_cb = (mutex_cb_t *)mutex_id; /* Check parameters */ if (RT_NULL == mutex_cb) { return osErrorParameter; } rt_mutex_detach(&(mutex_cb->mutex)); if (mutex_cb->flags & MALLOC_CB) rt_free(mutex_cb); return osOK; } #endif #ifdef RT_USING_SEMAPHORE osSemaphoreId_t osSemaphoreNew(uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) { char name[RT_NAME_MAX]; sem_cb_t *sem_cb; static rt_uint16_t semaphore_number = 0U; /* Check parameters */ if ((0U == max_count) || (initial_count > max_count)) { return RT_NULL; } if ((RT_NULL == attr) || (RT_NULL == attr->name)) { rt_snprintf(name, sizeof(name), "sem%02d", semaphore_number++); } else rt_snprintf(name, sizeof(name), "%s", attr->name); if ((RT_NULL == attr) || (RT_NULL == attr->cb_mem)) { sem_cb = rt_malloc(sizeof(sem_cb_t)); if (RT_NULL == sem_cb) return RT_NULL; rt_memset(sem_cb, 0, sizeof(sem_cb_t)); sem_cb->flags |= MALLOC_CB; } else { if (attr->cb_size >= sizeof(sem_cb_t)) { sem_cb = attr->cb_mem; sem_cb->flags = 0; } else return RT_NULL; } rt_sem_init(&(sem_cb->sem), name, initial_count, RT_IPC_FLAG_FIFO); return sem_cb; } /// Get name of a Semaphore object. /// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew. /// \return name as NULL terminated string. const char *osSemaphoreGetName(osSemaphoreId_t semaphore_id) { sem_cb_t *sem_cb = (sem_cb_t *)semaphore_id; /* Check parameters */ if ((RT_NULL == sem_cb) || (rt_object_get_type(&sem_cb->sem.parent.parent) != RT_Object_Class_Semaphore)) { return RT_NULL; } return sem_cb->sem.parent.parent.name; } /// Acquire a Semaphore token or timeout if no tokens are available. /// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew. /// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out. /// \return status code that indicates the execution status of the function. osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout) { rt_err_t result; sem_cb_t *sem_cb = (sem_cb_t *)semaphore_id; /* Check parameters */ if (RT_NULL == sem_cb) { return osErrorParameter; } if(timeout == osWaitForever) { timeout = RT_WAITING_FOREVER; } result = rt_sem_take(&(sem_cb->sem), timeout); if (RT_EOK == result) return osOK; else if (-RT_ETIMEOUT == result) { if (0U == timeout) return osErrorResource; else return osErrorTimeout; } else return osError; } /// Release a Semaphore token that was acquired by \ref osSemaphoreAcquire. /// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew. /// \return status code that indicates the execution status of the function. osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id) { rt_err_t result; sem_cb_t *sem_cb = (sem_cb_t *)semaphore_id; /* Check parameters */ if (RT_NULL == sem_cb) { return osErrorParameter; } result = rt_sem_release(&(sem_cb->sem)); if (RT_EOK == result) return osOK; else return osError; } /// Get current Semaphore token count. /// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew. /// \return number of tokens available. uint32_t osSemaphoreGetCount(osSemaphoreId_t semaphore_id) { sem_cb_t *sem_cb = (sem_cb_t *)semaphore_id; /* Check parameters */ if ((RT_NULL == sem_cb) || (rt_object_get_type(&sem_cb->sem.parent.parent) != RT_Object_Class_Semaphore)) { return 0U; } return sem_cb->sem.value; } /// Delete a Semaphore object. /// \param[in] semaphore_id semaphore ID obtained by \ref osSemaphoreNew. /// \return status code that indicates the execution status of the function. osStatus_t osSemaphoreDelete(osSemaphoreId_t semaphore_id) { sem_cb_t *sem_cb = (sem_cb_t *)semaphore_id; /* Check parameters */ if (RT_NULL == sem_cb) { return osErrorParameter; } rt_sem_detach(&(sem_cb->sem)); if (sem_cb->flags & MALLOC_CB) rt_free(sem_cb); return osOK; } #endif #ifdef RT_USING_MEMPOOL // ==== Memory Pool Management Functions ==== /// Create and Initialize a Memory Pool object. /// \param[in] block_count maximum number of memory blocks in memory pool. /// \param[in] block_size memory block size in bytes. /// \param[in] attr memory pool attributes; NULL: default values. /// \return memory pool ID for reference by other functions or NULL in case of error. osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size, const osMemoryPoolAttr_t *attr) { char name[RT_NAME_MAX]; void *mp_addr; rt_uint32_t mp_size; mempool_cb_t *mempool_cb; static rt_uint16_t memory_pool_number = 0U; /* Check parameters */ if ((0U == block_count) || (0U == block_size)) { return RT_NULL; } if ((RT_NULL == attr) || (RT_NULL == attr->name)) { rt_snprintf(name, sizeof(name), "mp%02d", memory_pool_number++); } else rt_snprintf(name, sizeof(name), "%s", attr->name); if ((RT_NULL == attr) || (RT_NULL == attr->cb_mem)) { mempool_cb = rt_malloc(sizeof(mempool_cb_t)); if (RT_NULL == mempool_cb) return RT_NULL; rt_memset(mempool_cb, 0, sizeof(mempool_cb_t)); mempool_cb->flags |= MALLOC_CB; } else { if (attr->cb_size >= sizeof(mempool_cb_t)) { mempool_cb = attr->cb_mem; mempool_cb->flags = 0; } else return RT_NULL; } if ((RT_NULL == attr) || (RT_NULL == attr->mp_mem)) { block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE); mp_size = (block_size + sizeof(rt_uint8_t *)) * block_count; mp_addr = rt_malloc((block_size + sizeof(rt_uint8_t *)) * block_count); if (RT_NULL == mp_addr) { if (mempool_cb->flags & MALLOC_CB) rt_free(mempool_cb); return RT_NULL; } mempool_cb->flags |= MALLOC_MEM; } else { mp_addr = (void *)(attr->mp_mem); mp_size = attr->mp_size; } rt_mp_init(&(mempool_cb->mp), name, mp_addr, mp_size, block_size); return mempool_cb; } /// Get name of a Memory Pool object. /// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew. /// \return name as NULL terminated string. const char *osMemoryPoolGetName(osMemoryPoolId_t mp_id) { mempool_cb_t *mempool_cb = (mempool_cb_t *)mp_id; /* Check parameters */ if ((RT_NULL == mempool_cb) || (rt_object_get_type(&mempool_cb->mp.parent) != RT_Object_Class_MemPool)) { return RT_NULL; } return mempool_cb->mp.parent.name; } /// Allocate a memory block from a Memory Pool. /// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew. /// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out. /// \return address of the allocated memory block or NULL in case of no memory is available. void *osMemoryPoolAlloc(osMemoryPoolId_t mp_id, uint32_t timeout) { mempool_cb_t *mempool_cb = (mempool_cb_t *)mp_id; /* Check parameters */ if (RT_NULL == mempool_cb) { return RT_NULL; } if(timeout == osWaitForever) { timeout = RT_WAITING_FOREVER; } return rt_mp_alloc(&(mempool_cb->mp), timeout); } /// Return an allocated memory block back to a Memory Pool. /// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew. /// \param[in] block address of the allocated memory block to be returned to the memory pool. /// \return status code that indicates the execution status of the function. osStatus_t osMemoryPoolFree(osMemoryPoolId_t mp_id, void *block) { mempool_cb_t *mempool_cb = (mempool_cb_t *)mp_id; /* Check parameters */ if (RT_NULL == mempool_cb) { return osErrorParameter; } rt_mp_free(block); return osOK; } /// Get maximum number of memory blocks in a Memory Pool. /// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew. /// \return maximum number of memory blocks. uint32_t osMemoryPoolGetCapacity(osMemoryPoolId_t mp_id) { mempool_cb_t *mempool_cb = (mempool_cb_t *)mp_id; /* Check parameters */ if ((RT_NULL == mempool_cb) || (rt_object_get_type(&mempool_cb->mp.parent) != RT_Object_Class_MemPool)) { return 0U; } return mempool_cb->mp.block_total_count; } /// Get memory block size in a Memory Pool. /// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew. /// \return memory block size in bytes. uint32_t osMemoryPoolGetBlockSize(osMemoryPoolId_t mp_id) { mempool_cb_t *mempool_cb = (mempool_cb_t *)mp_id; /* Check parameters */ if ((RT_NULL == mempool_cb) || (rt_object_get_type(&mempool_cb->mp.parent) != RT_Object_Class_MemPool)) { return 0U; } return mempool_cb->mp.block_size; } /// Get number of memory blocks used in a Memory Pool. /// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew. /// \return number of memory blocks used. uint32_t osMemoryPoolGetCount(osMemoryPoolId_t mp_id) { rt_size_t used_blocks; mempool_cb_t *mempool_cb = (mempool_cb_t *)mp_id; /* Check parameters */ if ((RT_NULL == mempool_cb) || (rt_object_get_type(&mempool_cb->mp.parent) != RT_Object_Class_MemPool)) { return 0U; } used_blocks = mempool_cb->mp.block_total_count - mempool_cb->mp.block_free_count; return (uint32_t)used_blocks; } /// Get number of memory blocks available in a Memory Pool. /// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew. /// \return number of memory blocks available. uint32_t osMemoryPoolGetSpace(osMemoryPoolId_t mp_id) { mempool_cb_t *mempool_cb = (mempool_cb_t *)mp_id; /* Check parameters */ if ((RT_NULL == mempool_cb) || (rt_object_get_type(&mempool_cb->mp.parent) != RT_Object_Class_MemPool)) { return 0U; } return mempool_cb->mp.block_free_count; } /// Delete a Memory Pool object. /// \param[in] mp_id memory pool ID obtained by \ref osMemoryPoolNew. /// \return status code that indicates the execution status of the function. osStatus_t osMemoryPoolDelete(osMemoryPoolId_t mp_id) { mempool_cb_t *mempool_cb = (mempool_cb_t *)mp_id; /* Check parameters */ if (RT_NULL == mempool_cb) { return osErrorParameter; } rt_mp_detach(&(mempool_cb->mp)); if (mempool_cb->flags & MALLOC_CB) rt_free(mempool_cb); if (mempool_cb->flags & MALLOC_MEM) rt_free(mempool_cb->mp.start_address); return osOK; } #endif #ifdef RT_USING_MESSAGEQUEUE // ==== Message Queue Management Functions ==== /// Create and Initialize a Message Queue object. /// \param[in] msg_count maximum number of messages in queue. /// \param[in] msg_size maximum message size in bytes. /// \param[in] attr message queue attributes; NULL: default values. /// \return message queue ID for reference by other functions or NULL in case of error. osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr) { char name[RT_NAME_MAX]; mq_cb_t *mq_cb; void *mq_addr; rt_uint32_t mq_size; static rt_uint16_t mq_number = 0U; /* Check parameters */ if ((0U == msg_count) || (0U == msg_size)) { return RT_NULL; } if ((RT_NULL == attr) || (RT_NULL == attr->name)) { rt_snprintf(name, sizeof(name), "mq%02d", mq_number++); } else rt_snprintf(name, sizeof(name), "%s", attr->name); if ((RT_NULL == attr) || (RT_NULL == attr->cb_mem)) { mq_cb = rt_malloc(sizeof(mq_cb_t)); if (RT_NULL == mq_cb) return RT_NULL; rt_memset(mq_cb, 0, sizeof(mq_cb_t)); mq_cb->flags |= MALLOC_CB; } else { if (attr->cb_size >= sizeof(mq_cb_t)) { mq_cb = attr->cb_mem; mq_cb->flags = 0; } else return RT_NULL; } mq_cb->init_msg_size = msg_size; if ((RT_NULL == attr) || (RT_NULL == attr->mq_mem)) { register rt_size_t msg_align_size; /* get correct message size */ msg_align_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE); mq_size = (msg_align_size + sizeof(struct rt_mq_message)) * msg_count; mq_addr = rt_malloc(mq_size); if (RT_NULL == mq_addr) { if (mq_cb->flags & MALLOC_CB) rt_free(mq_cb); return RT_NULL; } rt_memset(mq_addr, 0, sizeof(mq_size)); mq_cb->flags |= MALLOC_MEM; } else { mq_addr = (void *)(attr->mq_mem); mq_size = attr->mq_size; } rt_mq_init(&(mq_cb->mq), name, mq_addr, msg_size, mq_size, RT_IPC_FLAG_FIFO); return mq_cb; } /// Get name of a Message Queue object. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \return name as NULL terminated string. const char *osMessageQueueGetName(osMessageQueueId_t mq_id) { mq_cb_t *mq_cb = (mq_cb_t *)mq_id; /* Check parameters */ if ((RT_NULL == mq_cb) || (rt_object_get_type(&mq_cb->mq.parent.parent) != RT_Object_Class_MessageQueue)) { return RT_NULL; } return mq_cb->mq.parent.parent.name; } /// Put a Message into a Queue or timeout if Queue is full. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \param[in] msg_ptr pointer to buffer with message to put into a queue. /// \param[in] msg_prio message priority. /// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out. /// \return status code that indicates the execution status of the function. osStatus_t osMessageQueuePut(osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) { rt_err_t result; mq_cb_t *mq_cb = (mq_cb_t *)mq_id; /* Check parameters */ if (RT_NULL == mq_cb || (RT_NULL == msg_ptr)) { return osErrorParameter; } if(timeout == osWaitForever) { timeout = RT_WAITING_FOREVER; } result = rt_mq_send_wait(&(mq_cb->mq), (void *)msg_ptr, mq_cb->init_msg_size, timeout); if (RT_EOK == result) return osOK; else if (-RT_EFULL == result) return osErrorResource; else if (-RT_ETIMEOUT == result) { return osErrorTimeout; } else { return osError; } } /// Get a Message from a Queue or timeout if Queue is empty. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \param[out] msg_ptr pointer to buffer for message to get from a queue. /// \param[out] msg_prio pointer to buffer for message priority or NULL. /// \param[in] timeout \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out. /// \return status code that indicates the execution status of the function. #if defined(RT_VERSION_CHECK) && (RTTHREAD_VERSION >= RT_VERSION_CHECK(5, 0, 1)) osStatus_t osMessageQueueGet(osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) { rt_ssize_t result = 0; mq_cb_t *mq_cb = (mq_cb_t *)mq_id; /* Check parameters */ if (RT_NULL == mq_cb || (RT_NULL == msg_ptr)) { return osErrorParameter; } if(timeout == osWaitForever) { timeout = RT_WAITING_FOREVER; } result = rt_mq_recv(&(mq_cb->mq), msg_ptr, mq_cb->init_msg_size, timeout); if (result > 0) { return osOK; } else if (-RT_ETIMEOUT == result) { if (0U == timeout) return osErrorResource; return osErrorTimeout; } else return osError; } #else /* legacy version macros (<5.0.1) */ osStatus_t osMessageQueueGet(osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) { rt_err_t result; mq_cb_t *mq_cb = (mq_cb_t *)mq_id; /* Check parameters */ if (RT_NULL == mq_cb || (RT_NULL == msg_ptr)) { return osErrorParameter; } if(timeout == osWaitForever) { timeout = RT_WAITING_FOREVER; } result = rt_mq_recv(&(mq_cb->mq), msg_ptr, mq_cb->init_msg_size, timeout); if (RT_EOK == result) return osOK; else if (-RT_ETIMEOUT == result) { if (0U == timeout) return osErrorResource; return osErrorTimeout; } else return osError; } #endif /// Get maximum number of messages in a Message Queue. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \return maximum number of messages. uint32_t osMessageQueueGetCapacity(osMessageQueueId_t mq_id) { mq_cb_t *mq_cb = (mq_cb_t *)mq_id; /* Check parameters */ if ((RT_NULL == mq_cb) || (rt_object_get_type(&mq_cb->mq.parent.parent) != RT_Object_Class_MessageQueue)) { return 0U; } return mq_cb->mq.max_msgs; } /// Get maximum message size in a Memory Pool. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \return maximum message size in bytes. uint32_t osMessageQueueGetMsgSize(osMessageQueueId_t mq_id) { mq_cb_t *mq_cb = (mq_cb_t *)mq_id; /* Check parameters */; if ((RT_NULL == mq_cb) || (rt_object_get_type(&mq_cb->mq.parent.parent) != RT_Object_Class_MessageQueue)) { return 0U; } return mq_cb->mq.msg_size; } /// Get number of queued messages in a Message Queue. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \return number of queued messages. uint32_t osMessageQueueGetCount(osMessageQueueId_t mq_id) { mq_cb_t *mq_cb = (mq_cb_t *)mq_id; /* Check parameters */; if ((RT_NULL == mq_cb) || (rt_object_get_type(&mq_cb->mq.parent.parent) != RT_Object_Class_MessageQueue)) { return 0U; } return mq_cb->mq.entry; } /// Get number of available slots for messages in a Message Queue. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \return number of available slots for messages. uint32_t osMessageQueueGetSpace(osMessageQueueId_t mq_id) { mq_cb_t *mq_cb = (mq_cb_t *)mq_id; /* Check parameters */; if ((RT_NULL == mq_cb) || (rt_object_get_type(&mq_cb->mq.parent.parent) != RT_Object_Class_MessageQueue)) { return 0U; } return (mq_cb->mq.max_msgs - mq_cb->mq.entry); } /// Reset a Message Queue to initial empty state. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \return status code that indicates the execution status of the function. osStatus_t osMessageQueueReset(osMessageQueueId_t mq_id) { rt_err_t result; mq_cb_t *mq_cb = (mq_cb_t *)mq_id; /* Check parameters */; if (RT_NULL == mq_cb) { return osErrorParameter; } result = rt_mq_control(&(mq_cb->mq), RT_IPC_CMD_RESET, RT_NULL); if (RT_EOK == result) return osOK; else return osError; } /// Delete a Message Queue object. /// \param[in] mq_id message queue ID obtained by \ref osMessageQueueNew. /// \return status code that indicates the execution status of the function. osStatus_t osMessageQueueDelete(osMessageQueueId_t mq_id) { mq_cb_t *mq_cb = (mq_cb_t *)mq_id; /* Check parameters */; if (RT_NULL == mq_cb) { return osErrorParameter; } rt_mq_detach(&(mq_cb->mq)); if (mq_cb->flags & MALLOC_CB) rt_free(mq_cb); if (mq_cb->flags & MALLOC_MEM) rt_free(mq_cb->mq.msg_pool); return osOK; } #endif