576 lines
17 KiB
C
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);
|
|
}
|