/* Copyright (c) 2018 ARM Limited * * 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 * * http://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. */ // Includes // -------- #include "mbed_assert.h" #include "ipc_queue.h" #include "psa_defs.h" // API Implmentation // ----------------- void ipc_producer_queue_init(ipc_producer_queue_t *queue, ipc_base_queue_t *base_queue_mem, osMutexId_t mutex, osSemaphoreId_t full_queue_sem ) { MBED_ASSERT(queue != NULL); MBED_ASSERT(base_queue_mem != NULL); MBED_ASSERT(base_queue_mem->magic == IPC_QUEUE_BASE_MAGIC); MBED_ASSERT(mutex != NULL); MBED_ASSERT(full_queue_sem != NULL); queue->magic = IPC_QUEUE_PRODUCER_MAGIC; queue->read_idx = &(base_queue_mem->read_idx); queue->write_idx = &(base_queue_mem->write_idx); queue->data = base_queue_mem->data; queue->mutex = mutex; queue->full_queue_sem = full_queue_sem; } void ipc_consumer_queue_init(ipc_consumer_queue_t *queue, ipc_base_queue_t *base_queue_mem, osSemaphoreId_t read_sem ) { MBED_ASSERT(queue != NULL); MBED_ASSERT(base_queue_mem != NULL); MBED_ASSERT(base_queue_mem->magic == IPC_QUEUE_BASE_MAGIC); MBED_ASSERT(read_sem != NULL); queue->magic = IPC_QUEUE_CONSUMER_MAGIC; queue->read_idx = &(base_queue_mem->read_idx); queue->write_idx = &(base_queue_mem->write_idx); queue->data = base_queue_mem->data; queue->read_sem = read_sem; } void ipc_queue_enqueue(ipc_producer_queue_t *queue, ipc_queue_item_t queue_item ) { MBED_ASSERT(queue != NULL); MBED_ASSERT(queue->magic == IPC_QUEUE_PRODUCER_MAGIC); osStatus_t os_status = osMutexAcquire(queue->mutex, osWaitForever); MBED_ASSERT(osOK == os_status); // While queue is full, wait on full_queue_sem while (((*(queue->write_idx) + 1) % IPC_QUEUE_SLOTS) == *(queue->read_idx)) { os_status = osSemaphoreAcquire(queue->full_queue_sem, IPC_QUEUE_WAIT_ON_FULL_MS); MBED_ASSERT((osOK == os_status) || (osErrorTimeout == os_status)); } // Write data to queue (shallow copy) (queue->data)[*(queue->write_idx)] = queue_item; *(queue->write_idx) = ((*(queue->write_idx) + 1) % IPC_QUEUE_SLOTS); // If the queue was empty before the push, call the supplied CB function if (((*(queue->read_idx) + 1) % IPC_QUEUE_SLOTS) == *(queue->write_idx)) { on_new_item(); } os_status = osMutexRelease(queue->mutex); MBED_ASSERT(osOK == os_status); PSA_UNUSED(os_status); } void ipc_queue_drain(ipc_consumer_queue_t *queue) { MBED_ASSERT(queue != NULL); MBED_ASSERT(queue->magic == IPC_QUEUE_CONSUMER_MAGIC); // queue->read_sem is released when the queue becomes non empty osStatus_t os_status = osSemaphoreAcquire(queue->read_sem, IPC_QUEUE_WAIT_ON_EMPTY_MS); MBED_ASSERT((osOK == os_status) || (osErrorTimeout == os_status)); PSA_UNUSED(os_status); // While queue is not empty, keep on popping queue items while (*(queue->read_idx) != *(queue->write_idx)) { // Pop an item from the queue (shallow copy) ipc_queue_item_t popped_item = (queue->data)[*(queue->read_idx)]; *(queue->read_idx) = ((*(queue->read_idx) + 1) % IPC_QUEUE_SLOTS); // If queue was full before this pop, call the corresponding CB function if (((*(queue->write_idx) + 2) % IPC_QUEUE_SLOTS) == *(queue->read_idx)) { on_vacancy(); } on_popped_item(popped_item); } }