xmclib/CMSIS/RTOS2/RTX/Source/rtx_evflags.c
2024-10-17 17:09:59 +02:00

576 lines
17 KiB
C

/*
* Copyright (c) 2013-2017 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"
// ==== 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 == 0U)
uint32_t primask = __get_PRIMASK();
#endif
uint32_t event_flags;
#if (__EXCLUSIVE_ACCESS == 0U)
__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 == 0U)
uint32_t primask = __get_PRIMASK();
#endif
uint32_t event_flags;
#if (__EXCLUSIVE_ACCESS == 0U)
__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 == 0U)
uint32_t primask;
#endif
uint32_t event_flags;
if ((options & osFlagsNoClear) == 0U) {
#if (__EXCLUSIVE_ACCESS == 0U)
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;
}
// ==== Library functions ====
/// Event Flags post ISR processing.
/// \param[in] ef event flags object.
void osRtxEventFlagsPostProcess (os_event_flags_t *ef) {
os_thread_t *thread;
os_thread_t *thread_next;
uint32_t event_flags;
if (ef->state == osRtxObjectInactive) {
return;
}
// 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 ====
// Service Calls definitions
SVC0_1M(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)
/// Create and Initialize an Event Flags object.
/// \note API identical to osEventFlagsNew
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;
ef = attr->cb_mem;
if (ef != NULL) {
if (((uint32_t)ef & 3U) || (attr->cb_size < sizeof(os_event_flags_t))) {
EvrRtxEventFlagsError(NULL, osRtxErrorInvalidControlBlock);
return NULL;
}
} else {
if (attr->cb_size != 0U) {
EvrRtxEventFlagsError(NULL, osRtxErrorInvalidControlBlock);
return NULL;
}
}
} else {
name = NULL;
ef = NULL;
}
// Allocate object memory if not provided
if (ef == NULL) {
if (osRtxInfo.mpi.event_flags != NULL) {
ef = osRtxMemoryPoolAlloc(osRtxInfo.mpi.event_flags);
} else {
ef = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_event_flags_t), 1U);
}
if (ef == NULL) {
EvrRtxEventFlagsError(NULL, osErrorNoMemory);
return NULL;
}
flags = osRtxFlagSystemObject;
} else {
flags = 0U;
}
// Initialize control block
ef->id = osRtxIdEventFlags;
ef->state = osRtxObjectActive;
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);
return ef;
}
/// Get name of an Event Flags object.
/// \note API identical to osEventFlagsGetName
const char *svcRtxEventFlagsGetName (osEventFlagsId_t ef_id) {
os_event_flags_t *ef = (os_event_flags_t *)ef_id;
// Check parameters
if ((ef == NULL) || (ef->id != osRtxIdEventFlags)) {
EvrRtxEventFlagsGetName(ef, NULL);
return NULL;
}
// Check object state
if (ef->state == osRtxObjectInactive) {
EvrRtxEventFlagsGetName(ef, NULL);
return NULL;
}
EvrRtxEventFlagsGetName(ef, ef->name);
return ef->name;
}
/// Set the specified Event Flags.
/// \note API identical to osEventFlagsSet
uint32_t svcRtxEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags) {
os_event_flags_t *ef = (os_event_flags_t *)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 & ~((1U << osRtxEventFlagsLimit) - 1U))) {
EvrRtxEventFlagsError(ef, osErrorParameter);
return ((uint32_t)osErrorParameter);
}
// Check object state
if (ef->state == osRtxObjectInactive) {
EvrRtxEventFlagsError(ef, osErrorResource);
return ((uint32_t)osErrorResource);
}
// 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
uint32_t svcRtxEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags) {
os_event_flags_t *ef = (os_event_flags_t *)ef_id;
uint32_t event_flags;
// Check parameters
if ((ef == NULL) || (ef->id != osRtxIdEventFlags) ||
(flags & ~((1U << osRtxEventFlagsLimit) - 1U))) {
EvrRtxEventFlagsError(ef, osErrorParameter);
return ((uint32_t)osErrorParameter);
}
// Check object state
if (ef->state == osRtxObjectInactive) {
EvrRtxEventFlagsError(ef, osErrorResource);
return ((uint32_t)osErrorResource);
}
// 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
uint32_t svcRtxEventFlagsGet (osEventFlagsId_t ef_id) {
os_event_flags_t *ef = (os_event_flags_t *)ef_id;
// Check parameters
if ((ef == NULL) || (ef->id != osRtxIdEventFlags)) {
EvrRtxEventFlagsGet(ef, 0U);
return 0U;
}
// Check object state
if (ef->state == osRtxObjectInactive) {
EvrRtxEventFlagsGet(ef, 0U);
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
uint32_t svcRtxEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout) {
os_event_flags_t *ef = (os_event_flags_t *)ef_id;
os_thread_t *running_thread;
uint32_t event_flags;
running_thread = osRtxThreadGetRunning();
if (running_thread == NULL) {
EvrRtxEventFlagsError(ef, osRtxErrorKernelNotRunning);
return ((uint32_t)osError);
}
// Check parameters
if ((ef == NULL) || (ef->id != osRtxIdEventFlags) ||
(flags & ~((1U << osRtxEventFlagsLimit) - 1U))) {
EvrRtxEventFlagsError(ef, osErrorParameter);
return ((uint32_t)osErrorParameter);
}
// Check object state
if (ef->state == osRtxObjectInactive) {
EvrRtxEventFlagsError(ef, osErrorResource);
return ((uint32_t)osErrorResource);
}
// Check Event Flags
event_flags = EventFlagsCheck(ef, flags, options);
if (event_flags != 0U) {
EvrRtxEventFlagsWaitCompleted(ef, flags, options, event_flags);
return event_flags;
}
// Check if timeout is specified
if (timeout != 0U) {
EvrRtxEventFlagsWaitPending(ef, flags, options, timeout);
// Store waiting flags and options
running_thread->wait_flags = flags;
running_thread->flags_options = (uint8_t)options;
// Suspend current Thread
osRtxThreadListPut((os_object_t*)ef, running_thread);
osRtxThreadWaitEnter(osRtxThreadWaitingEventFlags, timeout);
return ((uint32_t)osErrorTimeout);
}
EvrRtxEventFlagsWaitNotCompleted(ef, flags, options);
return ((uint32_t)osErrorResource);
}
/// Delete an Event Flags object.
/// \note API identical to osEventFlagsDelete
osStatus_t svcRtxEventFlagsDelete (osEventFlagsId_t ef_id) {
os_event_flags_t *ef = (os_event_flags_t *)ef_id;
os_thread_t *thread;
// Check parameters
if ((ef == NULL) || (ef->id != osRtxIdEventFlags)) {
EvrRtxEventFlagsError(ef, osErrorParameter);
return osErrorParameter;
}
// Check object state
if (ef->state == osRtxObjectInactive) {
EvrRtxEventFlagsError(ef, osErrorResource);
return osErrorResource;
}
// Mark object as inactive
ef->state = osRtxObjectInactive;
// Unblock waiting threads
if (ef->thread_list != NULL) {
do {
thread = osRtxThreadListGet((os_object_t*)ef);
osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, false);
} while (ef->thread_list != NULL);
osRtxThreadDispatch(NULL);
}
// Free object memory
if (ef->flags & osRtxFlagSystemObject) {
if (osRtxInfo.mpi.event_flags != NULL) {
osRtxMemoryPoolFree(osRtxInfo.mpi.event_flags, ef);
} else {
osRtxMemoryFree(osRtxInfo.mem.common, ef);
}
}
EvrRtxEventFlagsDestroyed(ef);
return osOK;
}
// ==== 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 = (os_event_flags_t *)ef_id;
uint32_t event_flags;
// Check parameters
if ((ef == NULL) || (ef->id != osRtxIdEventFlags) ||
(flags & ~((1U << osRtxEventFlagsLimit) - 1U))) {
EvrRtxEventFlagsError(ef, osErrorParameter);
return ((uint32_t)osErrorParameter);
}
// Check object state
if (ef->state == osRtxObjectInactive) {
EvrRtxEventFlagsError(ef, osErrorResource);
return ((uint32_t)osErrorResource);
}
// Set Event Flags
event_flags = EventFlagsSet(ef, flags);
// Register post ISR processing
osRtxPostProcess((os_object_t *)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 = (os_event_flags_t *)ef_id;
uint32_t event_flags;
// Check parameters
if ((ef == NULL) || (ef->id != osRtxIdEventFlags) || (timeout != 0U) ||
(flags & ~((1U << osRtxEventFlagsLimit) - 1U))) {
EvrRtxEventFlagsError(ef, osErrorParameter);
return ((uint32_t)osErrorParameter);
}
// Check object state
if (ef->state == osRtxObjectInactive) {
EvrRtxEventFlagsError(ef, osErrorResource);
return ((uint32_t)osErrorResource);
}
// Check Event Flags
event_flags = EventFlagsCheck(ef, flags, options);
if (event_flags != 0U) {
EvrRtxEventFlagsWaitCompleted(ef, flags, options, event_flags);
return ((uint32_t)event_flags);
}
EvrRtxEventFlagsWaitNotCompleted(ef, flags, options);
return ((uint32_t)osErrorResource);
}
// ==== Public API ====
/// Create and Initialize an Event Flags object.
osEventFlagsId_t osEventFlagsNew (const osEventFlagsAttr_t *attr) {
EvrRtxEventFlagsNew(attr);
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
EvrRtxEventFlagsError(NULL, osErrorISR);
return NULL;
}
return __svcEventFlagsNew(attr);
}
/// Get name of an Event Flags object.
const char *osEventFlagsGetName (osEventFlagsId_t ef_id) {
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
EvrRtxEventFlagsGetName(ef_id, NULL);
return NULL;
}
return __svcEventFlagsGetName(ef_id);
}
/// Set the specified Event Flags.
uint32_t osEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags) {
EvrRtxEventFlagsSet(ef_id, flags);
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
return isrRtxEventFlagsSet(ef_id, flags);
} else {
return __svcEventFlagsSet(ef_id, flags);
}
}
/// Clear the specified Event Flags.
uint32_t osEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags) {
EvrRtxEventFlagsClear(ef_id, flags);
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
return svcRtxEventFlagsClear(ef_id, flags);
} else {
return __svcEventFlagsClear(ef_id, flags);
}
}
/// Get the current Event Flags.
uint32_t osEventFlagsGet (osEventFlagsId_t ef_id) {
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
return svcRtxEventFlagsGet(ef_id);
} else {
return __svcEventFlagsGet(ef_id);
}
}
/// 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) {
EvrRtxEventFlagsWait(ef_id, flags, options, timeout);
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
return isrRtxEventFlagsWait(ef_id, flags, options, timeout);
} else {
return __svcEventFlagsWait(ef_id, flags, options, timeout);
}
}
/// Delete an Event Flags object.
osStatus_t osEventFlagsDelete (osEventFlagsId_t ef_id) {
EvrRtxEventFlagsDelete(ef_id);
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
EvrRtxEventFlagsError(ef_id, osErrorISR);
return osErrorISR;
}
return __svcEventFlagsDelete(ef_id);
}