diff --git a/lib/cmsis_rtos_v2/CMakeLists.txt b/lib/cmsis_rtos_v2/CMakeLists.txt index c7cd3caa540..51146681928 100644 --- a/lib/cmsis_rtos_v2/CMakeLists.txt +++ b/lib/cmsis_rtos_v2/CMakeLists.txt @@ -13,6 +13,7 @@ zephyr_library_sources_ifdef( semaphore.c mempool.c msgq.c + event_flags.c ) zephyr_library_link_libraries(CMSIS) diff --git a/lib/cmsis_rtos_v2/Kconfig b/lib/cmsis_rtos_v2/Kconfig index 8770f701b58..1e2fb85c182 100644 --- a/lib/cmsis_rtos_v2/Kconfig +++ b/lib/cmsis_rtos_v2/Kconfig @@ -66,4 +66,11 @@ config CMSIS_V2_MSGQ_MAX_COUNT range 0 255 help Mention maximum number of message queues in CMSIS RTOS V2 compliant application. + +config CMSIS_V2_EVT_FLAGS_MAX_COUNT + int "Maximum event flags count in CMSIS RTOS V2 application" + default 5 + range 0 255 + help + Mention maximum number of event flags in CMSIS RTOS V2 compliant application. endif diff --git a/lib/cmsis_rtos_v2/event_flags.c b/lib/cmsis_rtos_v2/event_flags.c new file mode 100644 index 00000000000..8c31265f97d --- /dev/null +++ b/lib/cmsis_rtos_v2/event_flags.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "wrapper.h" + +K_MEM_SLAB_DEFINE(cv2_event_flags_slab, sizeof(struct cv2_event_flags), + CONFIG_CMSIS_V2_EVT_FLAGS_MAX_COUNT, 4); + +static const osEventFlagsAttr_t init_event_flags_attrs = { + .name = "ZephyrEvent", + .attr_bits = 0, + .cb_mem = NULL, + .cb_size = 0, +}; + +#define DONT_CARE (0) +#define NSEC_PER_MSEC (NSEC_PER_USEC * USEC_PER_MSEC) + +/** + * @brief Create and Initialize an Event Flags object. + */ +osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr) +{ + struct cv2_event_flags *events; + + if (k_is_in_isr()) { + return NULL; + } + + if (attr == NULL) { + attr = &init_event_flags_attrs; + } + + if (k_mem_slab_alloc(&cv2_event_flags_slab, (void **)&events, 100) + == 0) { + memset(events, 0, sizeof(struct cv2_event_flags)); + } else { + return NULL; + } + + k_poll_signal_init(&events->poll_signal); + k_poll_event_init(&events->poll_event, K_POLL_TYPE_SIGNAL, + K_POLL_MODE_NOTIFY_ONLY, &events->poll_signal); + events->signal_results = 0; + memcpy(events->name, attr->name, 16); + + return (osEventFlagsId_t)events; +} + +/** + * @brief Set the specified Event Flags. + */ +uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags) +{ + struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id; + int key; + + if ((ef_id == NULL) || (flags & 0x80000000)) { + return osFlagsErrorParameter; + } + + key = irq_lock(); + events->signal_results |= flags; + irq_unlock(key); + + k_poll_signal_raise(&events->poll_signal, DONT_CARE); + + return events->signal_results; +} + +/** + * @brief Clear the specified Event Flags. + */ +uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags) +{ + struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id; + int key; + u32_t sig; + + if ((ef_id == NULL) || (flags & 0x80000000)) { + return osFlagsErrorParameter; + } + + key = irq_lock(); + sig = events->signal_results; + events->signal_results &= ~(flags); + irq_unlock(key); + + return sig; +} + +/** + * @brief 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) +{ + struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id; + int retval, key; + u32_t sig; + u32_t time_delta_ms, timeout_ms = __ticks_to_ms(timeout); + u64_t time_stamp_start, hwclk_cycles_delta, time_delta_ns; + + /* Can be called from ISRs only if timeout is set to 0 */ + if (timeout > 0 && k_is_in_isr()) { + return osFlagsErrorUnknown; + } + + if ((ef_id == NULL) || (flags & 0x80000000)) { + return osFlagsErrorParameter; + } + + for (;;) { + + time_stamp_start = (u64_t)k_cycle_get_32(); + + switch (timeout) { + case 0: + retval = k_poll(&events->poll_event, 1, K_NO_WAIT); + break; + case osWaitForever: + retval = k_poll(&events->poll_event, 1, K_FOREVER); + break; + default: + retval = k_poll(&events->poll_event, 1, timeout_ms); + break; + } + + switch (retval) { + case 0: + break; + case -EAGAIN: + return osFlagsErrorTimeout; + default: + return osFlagsErrorUnknown; + } + + __ASSERT(events->poll_event.state == K_POLL_STATE_SIGNALED, + "event state not signalled!"); + __ASSERT(events->poll_event.signal->signaled == 1, + "event signaled is not 1"); + + /* Reset the states to facilitate the next trigger */ + events->poll_event.signal->signaled = 0; + events->poll_event.state = K_POLL_STATE_NOT_READY; + + if (options & osFlagsWaitAll) { + + /* Check if all events we are waiting on have + * been signalled + */ + if ((events->signal_results & flags) == flags) { + break; + } + + /* If we need to wait on more signals, we need to + * adjust the timeout value accordingly based on + * the time that has already elapsed. + */ + hwclk_cycles_delta = + (u64_t)k_cycle_get_32() - time_stamp_start; + + time_delta_ns = + (u32_t)SYS_CLOCK_HW_CYCLES_TO_NS(hwclk_cycles_delta); + + time_delta_ms = (u32_t)time_delta_ns/NSEC_PER_MSEC; + + if (timeout_ms > time_delta_ms) { + timeout_ms -= time_delta_ms; + } else { + timeout_ms = 0; + } + } else { + break; + } + } + + sig = events->signal_results; + if (!(options & osFlagsNoClear)) { + + /* Clear signal flags as the thread is ready now */ + key = irq_lock(); + events->signal_results &= ~(flags); + irq_unlock(key); + } + + return sig; +} + +/** + * @brief Get name of an Event Flags object. + */ +const char *osEventFlagsGetName(osEventFlagsId_t ef_id) +{ + struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id; + + if (!k_is_in_isr() && (ef_id != NULL)) { + return events->name; + } else { + return NULL; + } +} + +/** + * @brief Get the current Event Flags. + */ +uint32_t osEventFlagsGet(osEventFlagsId_t ef_id) +{ + struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id; + + if (ef_id == NULL) { + return 0; + } + + return events->signal_results; +} + +/** + * @brief Delete an Event Flags object. + */ +osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id) +{ + struct cv2_event_flags *events = (struct cv2_event_flags *)ef_id; + + if (ef_id == NULL) { + return osErrorResource; + } + + if (k_is_in_isr()) { + return osErrorISR; + } + + /* The status code "osErrorParameter" (the value of the parameter + * ef_id is incorrect) is not supported in Zephyr. + */ + + k_mem_slab_free(&cv2_event_flags_slab, (void *)&events); + + return osOK; +} diff --git a/lib/cmsis_rtos_v2/wrapper.h b/lib/cmsis_rtos_v2/wrapper.h index 0156de53a45..cf336026371 100644 --- a/lib/cmsis_rtos_v2/wrapper.h +++ b/lib/cmsis_rtos_v2/wrapper.h @@ -55,6 +55,13 @@ struct cv2_msgq { char name[16]; }; +struct cv2_event_flags { + struct k_poll_signal poll_signal; + struct k_poll_event poll_event; + u32_t signal_results; + char name[16]; +}; + extern osThreadId_t get_cmsis_thread_id(k_tid_t tid); extern void *is_cmsis_rtos_v2_thread(void *thread_id);