pinebuds/rtos/rtx5/rtx_evflags.c

593 lines
17 KiB
C

/*
* Copyright (c) 2013-2019 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* -----------------------------------------------------------------------------
*
* Project: CMSIS-RTOS RTX
* Title: Event Flags functions
*
* -----------------------------------------------------------------------------
*/
#include "rtx_lib.h"
// OS Runtime Object Memory Usage
#if ((defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0)))
osRtxObjectMemUsage_t osRtxEventFlagsMemUsage
__attribute__((section(".data.os.evflags.obj"))) = {0U, 0U, 0U};
#endif
// ==== Helper functions ====
/// Set Event Flags.
/// \param[in] ef event flags object.
/// \param[in] flags specifies the flags to set.
/// \return event flags after setting.
static uint32_t EventFlagsSet(os_event_flags_t *ef, uint32_t flags) {
#if (EXCLUSIVE_ACCESS == 0)
uint32_t primask = __get_PRIMASK();
#endif
uint32_t event_flags;
#if (EXCLUSIVE_ACCESS == 0)
__disable_irq();
ef->event_flags |= flags;
event_flags = ef->event_flags;
if (primask == 0U) {
__enable_irq();
}
#else
event_flags = atomic_set32(&ef->event_flags, flags);
#endif
return event_flags;
}
/// Clear Event Flags.
/// \param[in] ef event flags object.
/// \param[in] flags specifies the flags to clear.
/// \return event flags before clearing.
static uint32_t EventFlagsClear(os_event_flags_t *ef, uint32_t flags) {
#if (EXCLUSIVE_ACCESS == 0)
uint32_t primask = __get_PRIMASK();
#endif
uint32_t event_flags;
#if (EXCLUSIVE_ACCESS == 0)
__disable_irq();
event_flags = ef->event_flags;
ef->event_flags &= ~flags;
if (primask == 0U) {
__enable_irq();
}
#else
event_flags = atomic_clr32(&ef->event_flags, flags);
#endif
return event_flags;
}
/// Check Event Flags.
/// \param[in] ef event flags object.
/// \param[in] flags specifies the flags to check.
/// \param[in] options specifies flags options (osFlagsXxxx).
/// \return event flags before clearing or 0 if specified flags have not been
/// set.
static uint32_t EventFlagsCheck(os_event_flags_t *ef, uint32_t flags,
uint32_t options) {
#if (EXCLUSIVE_ACCESS == 0)
uint32_t primask;
#endif
uint32_t event_flags;
if ((options & osFlagsNoClear) == 0U) {
#if (EXCLUSIVE_ACCESS == 0)
primask = __get_PRIMASK();
__disable_irq();
event_flags = ef->event_flags;
if ((((options & osFlagsWaitAll) != 0U) &&
((event_flags & flags) != flags)) ||
(((options & osFlagsWaitAll) == 0U) && ((event_flags & flags) == 0U))) {
event_flags = 0U;
} else {
ef->event_flags &= ~flags;
}
if (primask == 0U) {
__enable_irq();
}
#else
if ((options & osFlagsWaitAll) != 0U) {
event_flags = atomic_chk32_all(&ef->event_flags, flags);
} else {
event_flags = atomic_chk32_any(&ef->event_flags, flags);
}
#endif
} else {
event_flags = ef->event_flags;
if ((((options & osFlagsWaitAll) != 0U) &&
((event_flags & flags) != flags)) ||
(((options & osFlagsWaitAll) == 0U) && ((event_flags & flags) == 0U))) {
event_flags = 0U;
}
}
return event_flags;
}
// ==== Post ISR processing ====
/// Event Flags post ISR processing.
/// \param[in] ef event flags object.
static void osRtxEventFlagsPostProcess(os_event_flags_t *ef) {
os_thread_t *thread;
os_thread_t *thread_next;
uint32_t event_flags;
// Check if Threads are waiting for Event Flags
thread = ef->thread_list;
while (thread != NULL) {
thread_next = thread->thread_next;
event_flags =
EventFlagsCheck(ef, thread->wait_flags, thread->flags_options);
if (event_flags != 0U) {
osRtxThreadListRemove(thread);
osRtxThreadWaitExit(thread, event_flags, FALSE);
EvrRtxEventFlagsWaitCompleted(ef, thread->wait_flags,
thread->flags_options, event_flags);
}
thread = thread_next;
}
}
// ==== Service Calls ====
/// Create and Initialize an Event Flags object.
/// \note API identical to osEventFlagsNew
static osEventFlagsId_t svcRtxEventFlagsNew(const osEventFlagsAttr_t *attr) {
os_event_flags_t *ef;
uint8_t flags;
const char *name;
// Process attributes
if (attr != NULL) {
name = attr->name;
// lint -e{9079} "conversion from pointer to void to pointer to other type"
// [MISRA Note 6]
ef = attr->cb_mem;
if (ef != NULL) {
// lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note
// 7]
if ((((uint32_t)ef & 3U) != 0U) ||
(attr->cb_size < sizeof(os_event_flags_t))) {
EvrRtxEventFlagsError(NULL, osRtxErrorInvalidControlBlock);
// lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
}
} else {
if (attr->cb_size != 0U) {
EvrRtxEventFlagsError(NULL, osRtxErrorInvalidControlBlock);
// lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
}
}
} else {
name = NULL;
ef = NULL;
}
// Allocate object memory if not provided
if (ef == NULL) {
if (osRtxInfo.mpi.event_flags != NULL) {
// lint -e{9079} "conversion from pointer to void to pointer to other
// type" [MISRA Note 5]
ef = osRtxMemoryPoolAlloc(osRtxInfo.mpi.event_flags);
} else {
// lint -e{9079} "conversion from pointer to void to pointer to other
// type" [MISRA Note 5]
ef = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_event_flags_t), 1U);
}
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
if (ef != NULL) {
uint32_t used;
osRtxEventFlagsMemUsage.cnt_alloc++;
used =
osRtxEventFlagsMemUsage.cnt_alloc - osRtxEventFlagsMemUsage.cnt_free;
if (osRtxEventFlagsMemUsage.max_used < used) {
osRtxEventFlagsMemUsage.max_used = used;
}
}
#endif
flags = osRtxFlagSystemObject;
} else {
flags = 0U;
}
if (ef != NULL) {
// Initialize control block
ef->id = osRtxIdEventFlags;
ef->flags = flags;
ef->name = name;
ef->thread_list = NULL;
ef->event_flags = 0U;
// Register post ISR processing function
osRtxInfo.post_process.event_flags = osRtxEventFlagsPostProcess;
EvrRtxEventFlagsCreated(ef, ef->name);
} else {
EvrRtxEventFlagsError(NULL, (int32_t)osErrorNoMemory);
}
return ef;
}
/// Get name of an Event Flags object.
/// \note API identical to osEventFlagsGetName
static const char *svcRtxEventFlagsGetName(osEventFlagsId_t ef_id) {
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
// Check parameters
if ((ef == NULL) || (ef->id != osRtxIdEventFlags)) {
EvrRtxEventFlagsGetName(ef, NULL);
// lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
}
EvrRtxEventFlagsGetName(ef, ef->name);
return ef->name;
}
/// Set the specified Event Flags.
/// \note API identical to osEventFlagsSet
static uint32_t svcRtxEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags) {
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
os_thread_t *thread;
os_thread_t *thread_next;
uint32_t event_flags;
uint32_t event_flags0;
// Check parameters
if ((ef == NULL) || (ef->id != osRtxIdEventFlags) ||
((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) {
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
// lint -e{904} "Return statement before end of function" [MISRA Note 1]
return ((uint32_t)osErrorParameter);
}
// Set Event Flags
event_flags = EventFlagsSet(ef, flags);
// Check if Threads are waiting for Event Flags
thread = ef->thread_list;
while (thread != NULL) {
thread_next = thread->thread_next;
event_flags0 =
EventFlagsCheck(ef, thread->wait_flags, thread->flags_options);
if (event_flags0 != 0U) {
if ((thread->flags_options & osFlagsNoClear) == 0U) {
event_flags = event_flags0 & ~thread->wait_flags;
} else {
event_flags = event_flags0;
}
osRtxThreadListRemove(thread);
osRtxThreadWaitExit(thread, event_flags0, FALSE);
EvrRtxEventFlagsWaitCompleted(ef, thread->wait_flags,
thread->flags_options, event_flags0);
}
thread = thread_next;
}
osRtxThreadDispatch(NULL);
EvrRtxEventFlagsSetDone(ef, event_flags);
return event_flags;
}
/// Clear the specified Event Flags.
/// \note API identical to osEventFlagsClear
static uint32_t svcRtxEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags) {
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
uint32_t event_flags;
// Check parameters
if ((ef == NULL) || (ef->id != osRtxIdEventFlags) ||
((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) {
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
// lint -e{904} "Return statement before end of function" [MISRA Note 1]
return ((uint32_t)osErrorParameter);
}
// Clear Event Flags
event_flags = EventFlagsClear(ef, flags);
EvrRtxEventFlagsClearDone(ef, event_flags);
return event_flags;
}
/// Get the current Event Flags.
/// \note API identical to osEventFlagsGet
static uint32_t svcRtxEventFlagsGet(osEventFlagsId_t ef_id) {
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
// Check parameters
if ((ef == NULL) || (ef->id != osRtxIdEventFlags)) {
EvrRtxEventFlagsGet(ef, 0U);
// lint -e{904} "Return statement before end of function" [MISRA Note 1]
return 0U;
}
EvrRtxEventFlagsGet(ef, ef->event_flags);
return ef->event_flags;
}
/// Wait for one or more Event Flags to become signaled.
/// \note API identical to osEventFlagsWait
static uint32_t svcRtxEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags,
uint32_t options, uint32_t timeout) {
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
os_thread_t *thread;
uint32_t event_flags;
// Check parameters
if ((ef == NULL) || (ef->id != osRtxIdEventFlags) ||
((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) {
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
// lint -e{904} "Return statement before end of function" [MISRA Note 1]
return ((uint32_t)osErrorParameter);
}
// Check Event Flags
event_flags = EventFlagsCheck(ef, flags, options);
if (event_flags != 0U) {
EvrRtxEventFlagsWaitCompleted(ef, flags, options, event_flags);
} else {
// Check if timeout is specified
if (timeout != 0U) {
EvrRtxEventFlagsWaitPending(ef, flags, options, timeout);
// Suspend current Thread
if (osRtxThreadWaitEnter(osRtxThreadWaitingEventFlags, timeout)) {
thread = osRtxThreadGetRunning();
osRtxThreadListPut(osRtxObject(ef), thread);
// Store waiting flags and options
thread->wait_flags = flags;
thread->flags_options = (uint8_t)options;
} else {
EvrRtxEventFlagsWaitTimeout(ef);
}
event_flags = (uint32_t)osErrorTimeout;
} else {
EvrRtxEventFlagsWaitNotCompleted(ef, flags, options);
event_flags = (uint32_t)osErrorResource;
}
}
return event_flags;
}
/// Delete an Event Flags object.
/// \note API identical to osEventFlagsDelete
static osStatus_t svcRtxEventFlagsDelete(osEventFlagsId_t ef_id) {
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
os_thread_t *thread;
// Check parameters
if ((ef == NULL) || (ef->id != osRtxIdEventFlags)) {
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
// lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
// Unblock waiting threads
if (ef->thread_list != NULL) {
do {
thread = osRtxThreadListGet(osRtxObject(ef));
osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
} while (ef->thread_list != NULL);
osRtxThreadDispatch(NULL);
}
// Mark object as invalid
ef->id = osRtxIdInvalid;
// Free object memory
if ((ef->flags & osRtxFlagSystemObject) != 0U) {
if (osRtxInfo.mpi.event_flags != NULL) {
(void)osRtxMemoryPoolFree(osRtxInfo.mpi.event_flags, ef);
} else {
(void)osRtxMemoryFree(osRtxInfo.mem.common, ef);
}
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
osRtxEventFlagsMemUsage.cnt_free++;
#endif
}
EvrRtxEventFlagsDestroyed(ef);
return osOK;
}
// Service Calls definitions
// lint ++flb "Library Begin" [MISRA Note 11]
SVC0_1(EventFlagsNew, osEventFlagsId_t, const osEventFlagsAttr_t *)
SVC0_1(EventFlagsGetName, const char *, osEventFlagsId_t)
SVC0_2(EventFlagsSet, uint32_t, osEventFlagsId_t, uint32_t)
SVC0_2(EventFlagsClear, uint32_t, osEventFlagsId_t, uint32_t)
SVC0_1(EventFlagsGet, uint32_t, osEventFlagsId_t)
SVC0_4(EventFlagsWait, uint32_t, osEventFlagsId_t, uint32_t, uint32_t, uint32_t)
SVC0_1(EventFlagsDelete, osStatus_t, osEventFlagsId_t)
// lint --flb "Library End"
// ==== ISR Calls ====
/// Set the specified Event Flags.
/// \note API identical to osEventFlagsSet
__STATIC_INLINE
uint32_t isrRtxEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags) {
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
uint32_t event_flags;
// Check parameters
if ((ef == NULL) || (ef->id != osRtxIdEventFlags) ||
((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) {
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
// lint -e{904} "Return statement before end of function" [MISRA Note 1]
return ((uint32_t)osErrorParameter);
}
// Set Event Flags
event_flags = EventFlagsSet(ef, flags);
// Register post ISR processing
osRtxPostProcess(osRtxObject(ef));
EvrRtxEventFlagsSetDone(ef, event_flags);
return event_flags;
}
/// Wait for one or more Event Flags to become signaled.
/// \note API identical to osEventFlagsWait
__STATIC_INLINE
uint32_t isrRtxEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags,
uint32_t options, uint32_t timeout) {
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
uint32_t event_flags;
// Check parameters
if ((ef == NULL) || (ef->id != osRtxIdEventFlags) || (timeout != 0U) ||
((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) {
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
// lint -e{904} "Return statement before end of function" [MISRA Note 1]
return ((uint32_t)osErrorParameter);
}
// Check Event Flags
event_flags = EventFlagsCheck(ef, flags, options);
if (event_flags != 0U) {
EvrRtxEventFlagsWaitCompleted(ef, flags, options, event_flags);
} else {
EvrRtxEventFlagsWaitNotCompleted(ef, flags, options);
event_flags = (uint32_t)osErrorResource;
}
return event_flags;
}
// ==== Public API ====
/// Create and Initialize an Event Flags object.
osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr) {
osEventFlagsId_t ef_id;
EvrRtxEventFlagsNew(attr);
if (IsIrqMode() || IsIrqMasked()) {
EvrRtxEventFlagsError(NULL, (int32_t)osErrorISR);
ef_id = NULL;
} else {
ef_id = __svcEventFlagsNew(attr);
}
return ef_id;
}
/// Get name of an Event Flags object.
const char *osEventFlagsGetName(osEventFlagsId_t ef_id) {
const char *name;
if (IsIrqMode() || IsIrqMasked()) {
EvrRtxEventFlagsGetName(ef_id, NULL);
name = NULL;
} else {
name = __svcEventFlagsGetName(ef_id);
}
return name;
}
/// Set the specified Event Flags.
uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags) {
uint32_t event_flags;
EvrRtxEventFlagsSet(ef_id, flags);
if (IsIrqMode() || IsIrqMasked()) {
event_flags = isrRtxEventFlagsSet(ef_id, flags);
} else {
event_flags = __svcEventFlagsSet(ef_id, flags);
}
return event_flags;
}
/// Clear the specified Event Flags.
uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags) {
uint32_t event_flags;
EvrRtxEventFlagsClear(ef_id, flags);
if (IsIrqMode() || IsIrqMasked()) {
event_flags = svcRtxEventFlagsClear(ef_id, flags);
} else {
event_flags = __svcEventFlagsClear(ef_id, flags);
}
return event_flags;
}
/// Get the current Event Flags.
uint32_t osEventFlagsGet(osEventFlagsId_t ef_id) {
uint32_t event_flags;
if (IsIrqMode() || IsIrqMasked()) {
event_flags = svcRtxEventFlagsGet(ef_id);
} else {
event_flags = __svcEventFlagsGet(ef_id);
}
return event_flags;
}
/// Wait for one or more Event Flags to become signaled.
uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags,
uint32_t options, uint32_t timeout) {
uint32_t event_flags;
EvrRtxEventFlagsWait(ef_id, flags, options, timeout);
if (IsIrqMode() || IsIrqMasked()) {
event_flags = isrRtxEventFlagsWait(ef_id, flags, options, timeout);
} else {
event_flags = __svcEventFlagsWait(ef_id, flags, options, timeout);
}
return event_flags;
}
/// Delete an Event Flags object.
osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id) {
osStatus_t status;
EvrRtxEventFlagsDelete(ef_id);
if (IsIrqMode() || IsIrqMasked()) {
EvrRtxEventFlagsError(ef_id, (int32_t)osErrorISR);
status = osErrorISR;
} else {
status = __svcEventFlagsDelete(ef_id);
}
return status;
}