diff --git a/include/audio_module/audio_module.h b/include/audio_module/audio_module.h index 640772cab2c6..e130d021dee2 100644 --- a/include/audio_module/audio_module.h +++ b/include/audio_module/audio_module.h @@ -23,6 +23,19 @@ extern "C" { #include "audio_defines.h" +/** + * @brief Helper macro to configure the modules parameters. + */ +#define AUDIO_MODULE_PARAMETERS(p, dest, sck, sck_size, pri, fifo_rx, fifo_tx, slab, slab_size) \ + (p).description = (dest); \ + (p).thread.stack = (sck); \ + (p).thread.stack_size = (sck_size); \ + (p).thread.priority = (pri); \ + (p).thread.msg_rx = (fifo_rx); \ + (p).thread.msg_tx = (fifo_tx); \ + (p).thread.data_slab = (slab); \ + (p).thread.data_size = (slab_size); + /** * @brief Number of valid location bits. */ @@ -409,6 +422,10 @@ int audio_module_stop(struct audio_module_handle *handle); /** * @brief Send an audio data item to an audio module, all data is consumed by the module. * + * @note: The data pointer and its associated size that are passed via the audio data + * pointer, can be NULL and/or 0. It is the responsibility of the low level module functions + * to handle this correctly. + * * @param handle [in/out] The handle for the receiving module instance. * @param audio_data [in] Pointer to the audio data to send to the module. * @param response_cb [in] Pointer to a callback to run when the buffer is @@ -423,6 +440,10 @@ int audio_module_data_tx(struct audio_module_handle *handle, /** * @brief Retrieve an audio data item from an audio module. * + * @note: The data pointer and its associated size that are passed via the audio data + * pointer, can be NULL and/or 0. It is the responsibility of the low level module functions + * to handle this correctly. + * * @param handle [in/out] The handle to the module instance. * @param audio_data [out] Pointer to the audio data from the module. * @param timeout [in] Non-negative waiting period to wait for operation to complete @@ -441,6 +462,10 @@ int audio_module_data_rx(struct audio_module_handle *handle, struct audio_data * * returned via the module or final module's output FIFO. All the input data is consumed * within the call and thus the input data buffer maybe released once the function returns. * + * @note: The data I/O pointers and their associated sizes that are passed via the audio data + * pointers, can be NULL and/or 0. It is the responsibility of the low level module functions + * to handle this correctly. + * * @param handle_tx [in/out] The handle to the module to send the input audio data to. * @param handle_rx [in/out] The handle to the module to receive audio data from. * @param audio_data_tx [in] Pointer to the audio data to send. diff --git a/include/audio_modules/audio_module_template.h b/include/audio_modules/audio_module_template.h new file mode 100644 index 000000000000..6142ddf4b8bb --- /dev/null +++ b/include/audio_modules/audio_module_template.h @@ -0,0 +1,50 @@ +/* + * Copyright(c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#ifndef _AUDIO_MODULE_TEMPLATE_H_ +#define _AUDIO_MODULE_TEMPLATE_H_ + +#include +#include +#include +#include "audio_defines.h" +#include "audio_module.h" + +#define AUDIO_MODULE_TEMPLATE_LAST_BYTES (10) + +/** + * @brief Private pointer to the module's parameters. + * + */ +extern struct audio_module_description *audio_module_template_description; + +/** + * @brief The module configuration structure. + * + */ +struct audio_module_template_configuration { + /* The rate. */ + uint32_t sample_rate_hz; + + /* the depth. */ + uint32_t bit_depth; + + /* A string .*/ + char *some_text; +}; + +/** + * @brief Private module context. + * + */ +struct audio_module_template_context { + /* Array of data to illustrate the data process function. */ + uint8_t audio_module_template_data[AUDIO_MODULE_TEMPLATE_LAST_BYTES]; + + /* The template configuration. */ + struct audio_module_template_configuration config; +}; + +#endif /* _AUDIO_MODULE_TEMPLATE_H_ */ diff --git a/include/data_fifo.h b/include/data_fifo.h index ea5b33bb3ff5..258e359d2ac1 100644 --- a/include/data_fifo.h +++ b/include/data_fifo.h @@ -43,14 +43,14 @@ struct data_fifo { #define DATA_FIFO_DEFINE(name, elements_max_in, block_size_max_in) \ char __aligned(WB_UP(1)) \ - _msgq_buffer_##name[(elements_max_in) * sizeof(struct data_fifo_msgq)] = { 0 }; \ + _msgq_buffer_##name[(elements_max_in) * sizeof(struct data_fifo_msgq)] = {0}; \ char __aligned(WB_UP(1)) \ - _slab_buffer_##name[(elements_max_in) * (block_size_max_in)] = { 0 }; \ - struct data_fifo name = { .msgq_buffer = _msgq_buffer_##name, \ - .slab_buffer = _slab_buffer_##name, \ - .block_size_max = block_size_max_in, \ - .elements_max = elements_max_in, \ - .initialized = false } + _slab_buffer_##name[(elements_max_in) * (block_size_max_in)] = {0}; \ + struct data_fifo name = {.msgq_buffer = _msgq_buffer_##name, \ + .slab_buffer = _slab_buffer_##name, \ + .block_size_max = block_size_max_in, \ + .elements_max = elements_max_in, \ + .initialized = false} /** * @brief Get pointer to the first vacant block in slab. @@ -150,6 +150,18 @@ int data_fifo_num_used_get(struct data_fifo *data_fifo, uint32_t *alloced_num, */ int data_fifo_empty(struct data_fifo *data_fifo); +/** + * @brief Deinitialize data_fifo. + * + * @note data_fifo is emptied first, so it is the user's responsibility to release any data items it + * has queued. The internal slab and message buffer are not released. + * + * @param data_fifo Pointer to the data_fifo structure. + * + * @retval 0 if success, error otherwise. + */ +int data_fifo_uninit(struct data_fifo *data_fifo); + /** * @brief Initialise the data_fifo. * diff --git a/lib/data_fifo/data_fifo.c b/lib/data_fifo/data_fifo.c index a3f77be96f9d..4a865b15bbed 100644 --- a/lib/data_fifo/data_fifo.c +++ b/lib/data_fifo/data_fifo.c @@ -167,6 +167,22 @@ int data_fifo_empty(struct data_fifo *data_fifo) return 0; } +int data_fifo_uninit(struct data_fifo *data_fifo) +{ + __ASSERT_NO_MSG(data_fifo != NULL); + __ASSERT_NO_MSG(data_fifo->initialized); + int ret; + + ret = data_fifo_empty(data_fifo); + if (ret) { + return ret; + } + + data_fifo->initialized = false; + + return 0; +} + int data_fifo_init(struct data_fifo *data_fifo) { __ASSERT_NO_MSG(data_fifo != NULL); diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt index 69306e035bc1..8ec0e1054414 100644 --- a/subsys/CMakeLists.txt +++ b/subsys/CMakeLists.txt @@ -69,6 +69,7 @@ add_subdirectory_ifdef(CONFIG_NRF_DM dm) add_subdirectory_ifdef(CONFIG_EMDS emds) add_subdirectory_ifdef(CONFIG_NET_CORE_MONITOR net_core_monitor) add_subdirectory_ifdef(CONFIG_AUDIO_MODULE audio_module) +add_subdirectory_ifdef(CONFIG_AUDIO_MODULE_TEMPLATE audio_modules/audio_module_template) add_subdirectory_ifdef(CONFIG_UART_ASYNC_ADAPTER uart_async_adapter) add_subdirectory_ifdef(CONFIG_SDFW_SERVICES_ENABLED sdfw_services) add_subdirectory(suit) diff --git a/subsys/Kconfig b/subsys/Kconfig index 4ad732ace0a1..196865d9b9c6 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -34,6 +34,7 @@ rsource "dm/Kconfig" rsource "nrf_security/Kconfig" rsource "net_core_monitor/Kconfig" rsource "audio_module/Kconfig" +rsource "audio_modules/audio_module_template/Kconfig" rsource "uart_async_adapter/Kconfig" rsource "trusted_storage/Kconfig" rsource "logging/Kconfig" diff --git a/subsys/audio_module/CMakeLists.txt b/subsys/audio_module/CMakeLists.txt index 674c375ff352..3057268b7e95 100644 --- a/subsys/audio_module/CMakeLists.txt +++ b/subsys/audio_module/CMakeLists.txt @@ -4,4 +4,7 @@ # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause # -target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/audio_module.c) +target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/audio_module.c +) + +target_include_directories(app PRIVATE ${ZEPHYR_NRF_MODULE_DIR}/include/audio_module) diff --git a/subsys/audio_module/Kconfig b/subsys/audio_module/Kconfig index f0ea1d118a3b..1a52346bd278 100644 --- a/subsys/audio_module/Kconfig +++ b/subsys/audio_module/Kconfig @@ -3,8 +3,7 @@ # # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause # - -menu "Audio Module" +menu "Audio Modules" config AUDIO_MODULE tristate "Enable the audio module" @@ -20,8 +19,12 @@ config AUDIO_MODULE_NAME_SIZE int "Maximum size for module naming in characters" default 20 +#----------------------------------------------------------------------------# +menu "Log levels" + module = AUDIO_MODULE module-str = audio_module source "subsys/logging/Kconfig.template.log_config" -endmenu # Audio Module +endmenu # Log levels +endmenu # Audio Modules diff --git a/subsys/audio_module/audio_module.c b/subsys/audio_module/audio_module.c index 846a0fb4d3b7..d60600b6938f 100644 --- a/subsys/audio_module/audio_module.c +++ b/subsys/audio_module/audio_module.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ -#include "audio_module/audio_module.h" +#include "audio_module.h" #include #include @@ -153,8 +153,10 @@ static void audio_data_release_cb(struct audio_module_handle_private *handle, } if (k_sem_count_get(&hdl->sem) == 0) { + LOG_DBG("Audio data has been consumed in module %s", hdl->name); + /* Audio data has been consumed by all modules so now can free the data memory. */ - k_mem_slab_free(hdl->thread.data_slab, (void **)&audio_data->data); + k_mem_slab_free(hdl->thread.data_slab, (void *)audio_data->data); } } @@ -185,14 +187,15 @@ static int data_tx(struct audio_module_handle *tx_handle, struct audio_module_ha } /* Copy. The audio data itself will remain in its original location. */ - memcpy(&data_msg_rx->audio_data, audio_data, sizeof(struct audio_data)); + memcpy((uint8_t *)&(data_msg_rx->audio_data), audio_data, + sizeof(struct audio_data)); data_msg_rx->tx_handle = tx_handle; data_msg_rx->response_cb = data_in_response_cb; ret = data_fifo_block_lock(rx_handle->thread.msg_rx, (void **)&data_msg_rx, sizeof(struct audio_module_message)); if (ret) { - data_fifo_block_free(rx_handle->thread.msg_rx, (void **)&data_msg_rx); + data_fifo_block_free(rx_handle->thread.msg_rx, (void *)data_msg_rx); LOG_WRN("Module %s failed to queue audio data, ret %d", rx_handle->name, ret); @@ -244,7 +247,7 @@ static int tx_fifo_put(struct audio_module_handle *handle, LOG_ERR("Failed to send audio data to output of module %s, ret %d", handle->name, ret); - data_fifo_block_free(handle->thread.msg_tx, (void **)&data_msg_tx); + data_fifo_block_free(handle->thread.msg_tx, (void *)data_msg_tx); ret = k_sem_take(&handle->sem, K_NO_WAIT); if (ret) { @@ -254,6 +257,8 @@ static int tx_fifo_put(struct audio_module_handle *handle, return ret; } + LOG_DBG("Sent audio data to output of module %s", handle->name); + return 0; } @@ -275,7 +280,7 @@ static int send_to_connected_modules(struct audio_module_handle *handle, LOG_WRN("Nowhere to send the audio data from module %s so releasing it", handle->name); - k_mem_slab_free(handle->thread.data_slab, (void **)audio_data->data); + k_mem_slab_free(handle->thread.data_slab, (void *)audio_data->data); return 0; } @@ -332,6 +337,8 @@ static int send_to_connected_modules(struct audio_module_handle *handle, return ret; } + + LOG_DBG("Sent audio data to TX message queue for module %s", handle->name); } return 0; @@ -367,7 +374,7 @@ static void module_thread_input(struct audio_module_handle *handle, void *p2, vo * will control the data flow. */ ret = k_mem_slab_alloc(handle->thread.data_slab, (void **)&data, K_NO_WAIT); - __ASSERT(ret, "No free data for module %s, ret %d", handle->name, ret); + __ASSERT(ret == 0, "No free data for module %s, ret %d", handle->name, ret); /* Configure new audio data. */ audio_data.data = data; @@ -377,7 +384,7 @@ static void module_thread_input(struct audio_module_handle *handle, void *p2, vo ret = handle->description->functions->data_process( (struct audio_module_handle_private *)handle, NULL, &audio_data); if (ret) { - k_mem_slab_free(handle->thread.data_slab, (void **)(&data)); + k_mem_slab_free(handle->thread.data_slab, (void *)(data)); LOG_ERR("Data process error in module %s, ret %d", handle->name, ret); continue; @@ -426,7 +433,7 @@ static void module_thread_output(struct audio_module_handle *handle, void *p2, v */ ret = data_fifo_pointer_last_filled_get(handle->thread.msg_rx, (void **)&msg_rx, &size, K_FOREVER); - __ASSERT(ret, "Module %s error in getting last filled", handle->name); + __ASSERT(ret == 0, "Module %s error in getting last filled", handle->name); LOG_DBG("Module %s new audio data received", handle->name); @@ -449,7 +456,7 @@ static void module_thread_output(struct audio_module_handle *handle, void *p2, v &msg_rx->audio_data); } - data_fifo_block_free(handle->thread.msg_rx, (void **)&msg_rx); + data_fifo_block_free(handle->thread.msg_rx, (void *)msg_rx); } CODE_UNREACHABLE; @@ -481,21 +488,17 @@ static void module_thread_in_out(struct audio_module_handle *handle, void *p2, v while (1) { data = NULL; - LOG_DBG("Module %s is waiting for audio data", handle->name); - /* Get a new input message. * Since this input message is queued outside the module, this will then control the * data flow. */ ret = data_fifo_pointer_last_filled_get(handle->thread.msg_rx, (void **)&msg_rx, &size, K_FOREVER); - __ASSERT(ret, "Module %s error in getting last filled", handle->name); - - LOG_DBG("Module %s new audio data received", handle->name); + __ASSERT(ret == 0, "Module %s error in getting last filled %d", handle->name, ret); /* Get a new output buffer. */ ret = k_mem_slab_alloc(handle->thread.data_slab, (void **)&data, K_NO_WAIT); - __ASSERT(ret, "No free data buffer for module %s, dropping input, ret %d", + __ASSERT(ret == 0, "No free data buffer for module %s, dropping input, ret %d", handle->name, ret); /* Configure new audio audio_data. */ @@ -513,9 +516,9 @@ static void module_thread_in_out(struct audio_module_handle *handle, void *p2, v &msg_rx->audio_data); } - data_fifo_block_free(handle->thread.msg_rx, (void **)(&msg_rx)); + data_fifo_block_free(handle->thread.msg_rx, (void *)(msg_rx)); - k_mem_slab_free(handle->thread.data_slab, (void **)(&data)); + k_mem_slab_free(handle->thread.data_slab, (void *)(data)); LOG_ERR("Data process error in module %s, ret %d", handle->name, ret); continue; @@ -529,7 +532,7 @@ static void module_thread_in_out(struct audio_module_handle *handle, void *p2, v &msg_rx->audio_data); } - data_fifo_block_free(handle->thread.msg_rx, (void **)&msg_rx); + data_fifo_block_free(handle->thread.msg_rx, (void *)msg_rx); } CODE_UNREACHABLE; @@ -562,7 +565,7 @@ int audio_module_open(struct audio_module_parameters const *const parameters, /* Clear handle to known state. */ memset(handle, 0, sizeof(struct audio_module_handle)); - /* Allocate the context memory. */ + /* Store poimter to the context. */ handle->context = context; memcpy(handle->name, name, CONFIG_AUDIO_MODULE_NAME_SIZE); @@ -660,11 +663,11 @@ int audio_module_close(struct audio_module_handle *handle) } if (handle->thread.msg_rx != NULL) { - data_fifo_empty(handle->thread.msg_rx); + data_fifo_uninit(handle->thread.msg_rx); } if (handle->thread.msg_tx != NULL) { - data_fifo_empty(handle->thread.msg_tx); + data_fifo_uninit(handle->thread.msg_tx); } /* @@ -674,6 +677,9 @@ int audio_module_close(struct audio_module_handle *handle) k_thread_abort(handle->thread_id); + /* Ensure module handle data is fully cleared. */ + memset(handle, 0, sizeof(struct audio_module_handle)); + LOG_DBG("Closed module %s", handle->name); return 0; @@ -829,6 +835,8 @@ int audio_module_connect(struct audio_module_handle *handle_from, return ret; } + LOG_DBG("Connection(s) created"); + return 0; } @@ -1011,8 +1019,8 @@ int audio_module_data_tx(struct audio_module_handle *handle, return -ECANCELED; } - if (audio_data == NULL || audio_data->data == NULL || audio_data->data_size == 0) { - LOG_ERR("Data parameter error for module %s", handle->name); + if (audio_data == NULL) { + LOG_ERR("Output audio data for module %s has a NULL pointer", handle->name); return -EINVAL; } @@ -1024,11 +1032,11 @@ int audio_module_data_rx(struct audio_module_handle *handle, struct audio_data * { int ret; - struct audio_module_message *msg_tx; - size_t msg_tx_size; + struct audio_module_message *msg_rx = NULL; + size_t msg_rx_size = 0; - if (handle == NULL) { - LOG_ERR("Module handle is NULL"); + if (handle == NULL || audio_data == NULL) { + LOG_ERR("Module handle or audio data pointer are NULL"); return -EINVAL; } @@ -1048,31 +1056,43 @@ int audio_module_data_rx(struct audio_module_handle *handle, struct audio_data * return -ECANCELED; } - if (audio_data == NULL || audio_data->data == NULL || audio_data->data_size == 0) { - LOG_ERR("Input audio data for module %s has NULL pointer or a zero size buffer", - handle->name); - return -EINVAL; - } - - ret = data_fifo_pointer_last_filled_get(handle->thread.msg_tx, (void **)&msg_tx, - &msg_tx_size, timeout); + ret = data_fifo_pointer_last_filled_get(handle->thread.msg_tx, (void **)&msg_rx, + &msg_rx_size, timeout); if (ret) { LOG_ERR("Failed to retrieve data from module %s, ret %d", handle->name, ret); return ret; } - if (msg_tx->audio_data.data == NULL || - msg_tx->audio_data.data_size > audio_data->data_size) { - LOG_ERR("Data output pointer NULL or not enough room for buffer from module %s", - handle->name); - ret = -EINVAL; + if (msg_rx == NULL) { + LOG_ERR("Failed to retrieve message from %s", handle->name); + return -ECANCELED; + } + + ret = 0; + + if (audio_data->data_size != 0) { + if (msg_rx->audio_data.data_size > audio_data->data_size) { + LOG_ERR("Not enough room for buffer from module %s", handle->name); + ret = -ECANCELED; + } else if (audio_data->data == NULL) { + LOG_WRN("Data pointer to buffer is NULL"); + } else { + memcpy(&audio_data->meta, &msg_rx->audio_data.meta, + sizeof(struct audio_metadata)); + memcpy((uint8_t *)audio_data->data, (uint8_t *)msg_rx->audio_data.data, + msg_rx->audio_data.data_size); + audio_data->data_size = msg_rx->audio_data.data_size; + } } else { - memcpy(&audio_data->meta, &msg_tx->audio_data.meta, sizeof(struct audio_metadata)); - memcpy((uint8_t *)audio_data->data, (uint8_t *)msg_tx->audio_data.data, - msg_tx->audio_data.data_size); + LOG_WRN("Data buffer size is 0"); + } + + if (msg_rx->response_cb != NULL) { + msg_rx->response_cb((struct audio_module_handle_private *)msg_rx->tx_handle, + &msg_rx->audio_data); } - data_fifo_block_free(handle->thread.msg_tx, (void **)&msg_tx); + data_fifo_block_free(handle->thread.msg_tx, (void *)msg_rx); return ret; } @@ -1117,41 +1137,43 @@ int audio_module_data_tx_rx(struct audio_module_handle *handle_tx, return -EINVAL; } - if (audio_data_tx->data == NULL || audio_data_tx->data_size == 0 || - audio_data_rx->data == NULL || audio_data_rx->data_size == 0) { - LOG_ERR("One or both of the have invalid output audio data"); - return -EINVAL; - } - - ret = data_tx(NULL, handle_tx, audio_data_tx, NULL); + ret = data_tx(NULL, handle_rx, audio_data_tx, NULL); if (ret) { LOG_ERR("Failed to send audio data to module %s, ret %d", handle_tx->name, ret); return ret; } - LOG_DBG("Wait for message on module %s TX queue", handle_rx->name); - - ret = data_fifo_pointer_last_filled_get(handle_rx->thread.msg_rx, (void **)&msg_rx, + ret = data_fifo_pointer_last_filled_get(handle_rx->thread.msg_tx, (void **)&msg_rx, &msg_rx_size, timeout); if (ret) { - LOG_ERR("Failed to retrieve audio data from module %s, ret %d", handle_rx->name, + LOG_ERR("Failed to retrieve audio data from module %s, ret %d", handle_tx->name, ret); return ret; } - if (msg_rx->audio_data.data == NULL || msg_rx->audio_data.data_size == 0) { - LOG_ERR("Data output buffer too small for received buffer from module %s " - "(%d)", - handle_rx->name, msg_rx->audio_data.data_size); - ret = -EINVAL; + if (audio_data_rx->data_size != 0) { + if (msg_rx->audio_data.data_size > audio_data_rx->data_size) { + LOG_ERR("Not enough room for buffer from module %s", handle_rx->name); + ret = -ECANCELED; + } else if (audio_data_rx->data == NULL) { + LOG_WRN("Data pointer to buffer is NULL"); + } else { + memcpy(&audio_data_rx->meta, &msg_rx->audio_data.meta, + sizeof(struct audio_metadata)); + memcpy((uint8_t *)audio_data_rx->data, (uint8_t *)msg_rx->audio_data.data, + msg_rx->audio_data.data_size); + audio_data_rx->data_size = msg_rx->audio_data.data_size; + } } else { - memcpy(&audio_data_rx->meta, &msg_rx->audio_data.meta, - sizeof(struct audio_metadata)); - memcpy((uint8_t *)audio_data_rx->data, (uint8_t *)msg_rx->audio_data.data, - msg_rx->audio_data.data_size); + LOG_WRN("Data buffer size is 0"); + } + + if (msg_rx->response_cb != NULL) { + msg_rx->response_cb((struct audio_module_handle_private *)msg_rx->tx_handle, + &msg_rx->audio_data); } - data_fifo_block_free(handle_rx->thread.msg_rx, (void **)&msg_rx); + data_fifo_block_free(handle_tx->thread.msg_tx, (void *)msg_rx); return ret; }; diff --git a/subsys/audio_modules/audio_module_template/CMakeLists.txt b/subsys/audio_modules/audio_module_template/CMakeLists.txt new file mode 100644 index 000000000000..41d86a5587ce --- /dev/null +++ b/subsys/audio_modules/audio_module_template/CMakeLists.txt @@ -0,0 +1,10 @@ +# +# Copyright (c) 2023 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/audio_module_template.c) + +target_include_directories(app PRIVATE ${ZEPHYR_NRF_MODULE_DIR}/include/audio_module + ${ZEPHYR_NRF_MODULE_DIR}/include/audio_modules) diff --git a/subsys/audio_modules/audio_module_template/Kconfig b/subsys/audio_modules/audio_module_template/Kconfig new file mode 100644 index 000000000000..e055063a721e --- /dev/null +++ b/subsys/audio_modules/audio_module_template/Kconfig @@ -0,0 +1,27 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# +menu "Audio Modules" + +config AUDIO_MODULE_TEMPLATE + bool "Audio module template" + help + Enable the audio module template, the + starting point for a new audio module + +if AUDIO_MODULE_TEMPLATE + +#----------------------------------------------------------------------------# +menu "Log levels" + +module = AUDIO_MODULE_TEMPLATE +module-str = audio_module +source "subsys/logging/Kconfig.template.log_config" + +endmenu # Log levels + +endif # AUDIO_MODULE_TEMPLATE + +endmenu # Audio Modules diff --git a/subsys/audio_modules/audio_module_template/audio_module_template.c b/subsys/audio_modules/audio_module_template/audio_module_template.c new file mode 100644 index 000000000000..18b55c28a98c --- /dev/null +++ b/subsys/audio_modules/audio_module_template/audio_module_template.c @@ -0,0 +1,200 @@ +/* + * Copyright(c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#include "audio_module_template.h" + +#include +#include +#include +#include +#include +#include +#include "audio_defines.h" +#include "audio_module.h" + +#include +LOG_MODULE_REGISTER(audio_module_template, CONFIG_AUDIO_MODULE_TEMPLATE_LOG_LEVEL); + +static int audio_module_template_open(struct audio_module_handle_private *handle, + struct audio_module_configuration const *const configuration) + +{ + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + struct audio_module_template_context *ctx = + (struct audio_module_template_context *)hdl->context; + struct audio_module_template_configuration *config = + (struct audio_module_template_configuration *)configuration; + + /* Perform any other functions required to open the module. */ + + /* For example: Clear the module's context. + * Save the initial configuration to the module context. + */ + memset(ctx, 0, sizeof(struct audio_module_template_context)); + memcpy(&ctx->config, config, sizeof(struct audio_module_template_configuration)); + + LOG_DBG("Open %s module", hdl->name); + + return 0; +} + +static int audio_module_template_close(struct audio_module_handle_private *handle) +{ + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + struct audio_module_template_context *ctx = + (struct audio_module_template_context *)hdl->context; + + /* Perform any other functions required to close the module. */ + + /* For example: Clear the context data */ + memset(ctx, 0, sizeof(struct audio_module_template_context)); + + LOG_DBG("Close %s module", hdl->name); + + return 0; +} + +static int audio_module_template_configuration_set( + struct audio_module_handle_private *handle, + struct audio_module_configuration const *const configuration) +{ + struct audio_module_template_configuration *config = + (struct audio_module_template_configuration *)configuration; + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + struct audio_module_template_context *ctx = + (struct audio_module_template_context *)hdl->context; + + /* Perform any other functions to configure the module. */ + + /* For example: Copy the configuration into the context. */ + memcpy(&ctx->config, config, sizeof(struct audio_module_template_configuration)); + + LOG_DBG("Set the configuration for %s module: rate = %d depth = %d string = %s", + hdl->name, ctx->config.sample_rate_hz, ctx->config.bit_depth, + ctx->config.some_text); + + return 0; +} + +static int +audio_module_template_configuration_get(struct audio_module_handle_private const *const handle, + struct audio_module_configuration *configuration) +{ + struct audio_module_template_configuration *config = + (struct audio_module_template_configuration *)configuration; + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + struct audio_module_template_context *ctx = + (struct audio_module_template_context *)hdl->context; + + /* Perform any other functions to extract the configuration of the module. */ + + /* For example: Copy the configuration from the context into the output configuration. */ + memcpy(config, &ctx->config, sizeof(struct audio_module_template_configuration)); + + LOG_DBG("Get the configuration for %s module: rate = %d depth = %d string = %s", + hdl->name, config->sample_rate_hz, config->bit_depth, config->some_text); + + return 0; +} + +static int audio_module_template_start(struct audio_module_handle_private *handle) +{ + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + + /* Perform any other functions to start the module. */ + + LOG_DBG("Start the %s module", hdl->name); + + return 0; +} + +static int audio_module_template_stop(struct audio_module_handle_private *handle) +{ + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + + /* Perform any other functions to stop the module. */ + + LOG_DBG("Stop the %s module", hdl->name); + + return 0; +} + +static int audio_module_template_data_process(struct audio_module_handle_private *handle, + struct audio_data const *const audio_data_in, + struct audio_data *audio_data_out) +{ + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + + /* Perform any other functions to process the data within the module. */ + + /* For example: Copy the input to the output. */ + { + size_t size = audio_data_in->data_size < audio_data_out->data_size + ? audio_data_in->data_size + : audio_data_out->data_size; + + memcpy(&audio_data_out->meta, &audio_data_in->meta, sizeof(struct audio_metadata)); + memcpy((uint8_t *)audio_data_out->data, (uint8_t *)audio_data_in->data, size); + audio_data_out->data_size = size; + } + + LOG_DBG("Process the input audio data into the output audio data item for %s module", + hdl->name); + + return 0; +} + +/** + * @brief Table of the dummy module functions. + */ +const struct audio_module_functions audio_module_template_functions = { + /** + * @brief Function to an open the dummy module. + */ + .open = audio_module_template_open, + + /** + * @brief Function to close the dummy module. + */ + .close = audio_module_template_close, + + /** + * @brief Function to set the configuration of the dummy module. + */ + .configuration_set = audio_module_template_configuration_set, + + /** + * @brief Function to get the configuration of the dummy module. + */ + .configuration_get = audio_module_template_configuration_get, + + /** + * @brief Start a module processing data. + */ + .start = audio_module_template_start, + + /** + * @brief Pause a module processing data. + */ + .stop = audio_module_template_stop, + + /** + * @brief The core data processing function in the dummy module. + */ + .data_process = audio_module_template_data_process, +}; + +/** + * @brief The set-up description for the LC3 decoder. + */ +struct audio_module_description audio_module_template_dept = { + .name = "Audio Module Temp", + .type = AUDIO_MODULE_TYPE_IN_OUT, + .functions = &audio_module_template_functions}; + +/** + * @brief A private pointer to the LC3 decoder set-up parameters. + */ +struct audio_module_description *audio_module_template_description = &audio_module_template_dept; diff --git a/tests/lib/data_fifo/src/main.c b/tests/lib/data_fifo/src/main.c index 885cb8ad36c1..e0c37866f093 100644 --- a/tests/lib/data_fifo/src/main.c +++ b/tests/lib/data_fifo/src/main.c @@ -31,6 +31,48 @@ static void internal_test_remaining_elements(struct data_fifo *data_fifo, uint32 num_locked, line); } +ZTEST(suite_data_fifo, test_data_fifo_uninit_ok) +{ +#define BLOCKS_NUM 10 + DATA_FIFO_DEFINE(data_fifo, 10, 128); + + int ret; + + ret = data_fifo_init(&data_fifo); + zassert_equal(ret, 0, "init did not return 0"); + zassert_equal(data_fifo.initialized, true, "init did not set initialize flag"); + + uint8_t *data_ptr; + size_t data_size = 5; + + for (uint32_t i = 0; i < BLOCKS_NUM; i++) { + ret = data_fifo_pointer_first_vacant_get(&data_fifo, (void **)&data_ptr, K_NO_WAIT); + zassert_equal(ret, 0, "first_vacant_get did not return 0"); + data_ptr[0] = 0xa1; + data_ptr[1] = 0xa2; + data_ptr[2] = 0xa3; + data_ptr[3] = 0xa4; + data_ptr[4] = 0xa5; + + internal_test_remaining_elements(&data_fifo, i + 1, i, __LINE__); + + ret = data_fifo_block_lock(&data_fifo, (void **)&data_ptr, data_size); + zassert_equal(ret, 0, "block_lock did not return 0"); + + internal_test_remaining_elements(&data_fifo, i + 1, i + 1, __LINE__); + } + + ret = data_fifo_uninit(&data_fifo); + zassert_equal(ret, 0, "deinit did not return 0"); + zassert_equal(data_fifo.initialized, false, "deinit did not reset initialize flag"); + + ret = data_fifo_init(&data_fifo); + zassert_equal(ret, 0, "init did not return 0"); + zassert_equal(data_fifo.initialized, true, "init did not set initialize flag"); + + internal_test_remaining_elements(&data_fifo, 0, 0, __LINE__); +} + ZTEST(suite_data_fifo, test_data_fifo_init_ok) { DATA_FIFO_DEFINE(data_fifo, 8, 128); @@ -61,7 +103,7 @@ ZTEST(suite_data_fifo, test_data_fifo_data_put_get_ok) data_ptr[2] = 0xa3; data_ptr[3] = 0xa4; data_ptr[4] = 0xa5; - uint8_t data_1[DATA_SIZE] = { 0xa1, 0xa2, 0xa3, 0xa4, 0xa5 }; + uint8_t data_1[DATA_SIZE] = {0xa1, 0xa2, 0xa3, 0xa4, 0xa5}; internal_test_remaining_elements(&data_fifo, 1, 0, __LINE__); @@ -79,7 +121,7 @@ ZTEST(suite_data_fifo, test_data_fifo_data_put_get_ok) data_ptr[3] = 0xb4; data_ptr[4] = 0xb5; data_ptr[5] = 0xb6; - uint8_t data_2[DATA_SIZE + 1] = { 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6 }; + uint8_t data_2[DATA_SIZE + 1] = {0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6}; internal_test_remaining_elements(&data_fifo, 2, 1, __LINE__); diff --git a/tests/subsys/audio_module/prj.conf b/tests/subsys/audio_module/prj.conf index 0c4676358ce7..b4bee6c7511e 100644 --- a/tests/subsys/audio_module/prj.conf +++ b/tests/subsys/audio_module/prj.conf @@ -1,5 +1,5 @@ # -# Copyright (c) 2023 Nordic Semiconductor ASA +# Copyright (c) 2024 Nordic Semiconductor ASA # # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause # diff --git a/tests/subsys/audio_module/src/audio_module_test_common.c b/tests/subsys/audio_module/src/audio_module_test_common.c index 00964ac66768..786326cce16a 100644 --- a/tests/subsys/audio_module/src/audio_module_test_common.c +++ b/tests/subsys/audio_module/src/audio_module_test_common.c @@ -8,7 +8,8 @@ #include #include "audio_module_test_common.h" -#include "audio_module/audio_module.h" +#include "audio_module.h" +#include "fakes.h" const char *TEST_INSTANCE_NAME = "Test instance"; const char *TEST_STRING = "This is a test string"; @@ -19,6 +20,7 @@ void test_context_set(struct mod_context *ctx, struct mod_config const *const co memcpy(&ctx->test_string, TEST_STRING, sizeof(TEST_STRING)); ctx->test_uint32 = TEST_UINT32; memcpy(&ctx->config, config, sizeof(struct mod_config)); + reset_fake_fifo_counter(); } int test_open_function(struct audio_module_handle_private *handle, @@ -96,7 +98,10 @@ int test_data_process_function(struct audio_module_handle_private *handle, ARG_UNUSED(handle); memcpy(audio_data_tx, audio_data_rx, sizeof(struct audio_data)); - memcpy(audio_data_tx->data, audio_data_rx->data, audio_data_rx->data_size); + + if (audio_data_rx->data != NULL && audio_data_tx->data != NULL) { + memcpy(audio_data_tx->data, audio_data_rx->data, audio_data_rx->data_size); + } audio_data_tx->data_size = audio_data_rx->data_size; return 0; diff --git a/tests/subsys/audio_module/src/audio_module_test_common.h b/tests/subsys/audio_module/src/audio_module_test_common.h index 61c8c847895b..c5668c3c2a05 100644 --- a/tests/subsys/audio_module/src/audio_module_test_common.h +++ b/tests/subsys/audio_module/src/audio_module_test_common.h @@ -7,7 +7,7 @@ #ifndef _COMMON_AUDIO_MODULE_TEST_H_ #define _COMMON_AUDIO_MODULE_TEST_H_ -#include "audio_module/audio_module.h" +#include "audio_module.h" #define FAKE_FIFO_MSG_QUEUE_SIZE (4) #define FAKE_FIFO_MSG_QUEUE_DATA_SIZE (sizeof(struct audio_module_message)) @@ -18,6 +18,7 @@ #define TEST_CONNECTIONS_NUM (5) #define TEST_MODULES_NUM (TEST_CONNECTIONS_NUM - 1) #define TEST_MOD_DATA_SIZE (40) +#define TEST_AUDIO_DATA_ITEMS_NUM (20) struct mod_config { int test_int1; diff --git a/tests/subsys/audio_module/src/bad_param_test.c b/tests/subsys/audio_module/src/bad_param_test.c index 1439aae03332..520e198e31d5 100644 --- a/tests/subsys/audio_module/src/bad_param_test.c +++ b/tests/subsys/audio_module/src/bad_param_test.c @@ -8,7 +8,7 @@ #include #include "fakes.h" -#include "audio_module/audio_module.h" +#include "audio_module.h" #include "audio_module_test_common.h" static struct audio_module_functions mod_1_functions = {.open = NULL, @@ -26,7 +26,7 @@ static struct audio_module_configuration *config = (struct audio_module_configuration *)&configuration; static struct audio_module_handle handle, handle_tx, handle_rx; static struct mod_context context; -static uint8_t test_data[FAKE_FIFO_MSG_QUEUE_DATA_SIZE]; +static uint8_t test_data[TEST_MOD_DATA_SIZE]; static struct data_fifo mod_fifo_tx, mod_fifo_rx; static struct audio_data test_block, test_block_tx, test_block_rx; static char mod_thread_stack[TEST_MOD_THREAD_STACK_SIZE]; @@ -155,7 +155,7 @@ ZTEST(suite_audio_module_bad_param, test_data_tx_bad_state) NULL, &mod_fifo_rx); test_block.data = &test_data[0]; - test_block.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_tx(&handle, &test_block, NULL); zassert_equal(ret, -ECANCELED, "Data TX function did not return -EALREADY (%d): ret %d", @@ -199,11 +199,7 @@ ZTEST(suite_audio_module_bad_param, test_data_tx_null) NULL, NULL); test_block.data = &test_data[0]; - test_block.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; - - ret = audio_module_data_tx(NULL, &test_block, NULL); - zassert_equal(ret, -EINVAL, "Data TX function did not return -EINVAL (%d): ret %d", -EINVAL, - ret); + test_block.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_tx(&handle, &test_block, NULL); zassert_equal(ret, -ECANCELED, "Data TX function did not return -ECANCELED (%d): ret %d", @@ -214,20 +210,6 @@ ZTEST(suite_audio_module_bad_param, test_data_tx_null) ret = audio_module_data_tx(&handle, NULL, NULL); zassert_equal(ret, -EINVAL, "Data TX function did not return -EINVAL (%d): ret %d", -EINVAL, ret); - - test_block.data = NULL; - test_block.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; - - ret = audio_module_data_tx(&handle, &test_block, NULL); - zassert_equal(ret, -EINVAL, "Data TX function did not return -EINVAL (%d): ret %d", -EINVAL, - ret); - - test_block.data = &test_data[0]; - test_block.data_size = 0; - - ret = audio_module_data_tx(&handle, &test_block, NULL); - zassert_equal(ret, -EINVAL, "Data TX function did not return -EINVAL (%d): ret %d", -EINVAL, - ret); } ZTEST(suite_audio_module_bad_param, test_data_rx_bad_state) @@ -241,7 +223,7 @@ ZTEST(suite_audio_module_bad_param, test_data_rx_bad_state) &mod_fifo_tx, NULL); test_block.data = &test_data[0]; - test_block.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_rx(&handle, &test_block, K_NO_WAIT); zassert_equal(ret, -ECANCELED, "Data RX function did not return -ECANCELED (%d): ret %d", @@ -285,7 +267,7 @@ ZTEST(suite_audio_module_bad_param, test_data_rx_null) NULL, NULL); test_block.data = &test_data[0]; - test_block.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_rx(NULL, &test_block, K_NO_WAIT); zassert_equal(ret, -EINVAL, "Data RX function did not return -EINVAL (%d): ret %d", -EINVAL, @@ -302,18 +284,18 @@ ZTEST(suite_audio_module_bad_param, test_data_rx_null) ret); test_block.data = NULL; - test_block.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_rx(&handle, &test_block, K_NO_WAIT); - zassert_equal(ret, -EINVAL, "Data RX function did not return -EINVAL (%d): ret %d", -EINVAL, - ret); + zassert_equal(ret, -ECANCELED, "Data RX function did not return -ECANCELED (%d): ret %d", + -ECANCELED, ret); test_block.data = &test_data[0]; test_block.data_size = 0; ret = audio_module_data_rx(&handle, &test_block, K_NO_WAIT); - zassert_equal(ret, -EINVAL, "Data RX function did not return -EINVAL (%d): ret %d", -EINVAL, - ret); + zassert_equal(ret, -ECANCELED, "Data RX function did not return -ECANCELED (%d): ret %d", + -ECANCELED, ret); } ZTEST(suite_audio_module_bad_param, test_data_tx_rx_bad_state) @@ -331,9 +313,9 @@ ZTEST(suite_audio_module_bad_param, test_data_tx_rx_bad_state) AUDIO_MODULE_STATE_RUNNING, &mod_fifo_tx, &mod_fifo_rx); test_block_tx.data = &test_data[0]; - test_block_tx.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block_tx.data_size = TEST_MOD_DATA_SIZE; test_block_rx.data = &test_data[0]; - test_block_rx.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block_rx.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_tx_rx(&handle_tx, &handle_rx, &test_block_tx, &test_block_rx, K_NO_WAIT); @@ -424,9 +406,9 @@ ZTEST(suite_audio_module_bad_param, test_data_tx_rx_null) AUDIO_MODULE_STATE_RUNNING, NULL, NULL); test_block_tx.data = &test_data[0]; - test_block_tx.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block_tx.data_size = TEST_MOD_DATA_SIZE; test_block_rx.data = &test_data[0]; - test_block_rx.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block_rx.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_tx_rx(NULL, &handle_rx, &test_block_tx, &test_block_rx, K_NO_WAIT); zassert_equal(ret, -EINVAL, "Data TX/RX function did not return -EINVAL (%d): ret %d", @@ -459,7 +441,7 @@ ZTEST(suite_audio_module_bad_param, test_data_tx_rx_null) -EINVAL, ret); test_block_tx.data = NULL; - test_block_tx.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block_tx.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_tx_rx(&handle_tx, &handle_rx, &test_block_tx, &test_block_rx, K_NO_WAIT); @@ -475,9 +457,9 @@ ZTEST(suite_audio_module_bad_param, test_data_tx_rx_null) -EINVAL, ret); test_block_tx.data = &test_data[0]; - test_block_tx.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block_tx.data_size = TEST_MOD_DATA_SIZE; test_block_rx.data = NULL; - test_block_rx.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block_rx.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_tx_rx(&handle_tx, &handle_rx, &test_block_tx, &test_block_rx, K_NO_WAIT); diff --git a/tests/subsys/audio_module/src/fakes.c b/tests/subsys/audio_module/src/fakes.c index a00a269bdb61..acb8cef8645d 100644 --- a/tests/subsys/audio_module/src/fakes.c +++ b/tests/subsys/audio_module/src/fakes.c @@ -12,13 +12,13 @@ #include "fakes.h" /* Overload the message buffer pointer with a point to one of the an arrays below */ -static int fifo_num; +int fifo_num; struct test_slab_queue { size_t head; size_t tail; size_t size; - size_t locked; + struct k_sem sem; void **data[FAKE_FIFO_MSG_QUEUE_SIZE]; struct audio_module_message msg[FAKE_FIFO_MSG_QUEUE_SIZE]; @@ -28,26 +28,17 @@ struct test_msg_fifo_queue { size_t head; size_t tail; size_t size; - size_t locked; + struct k_sem sem; void **data[FAKE_FIFO_MSG_QUEUE_SIZE]; }; +/* FIFO "slab" */ static struct test_slab_queue test_fifo_slab[FAKE_FIFO_NUM]; +/* FIFO "message" queue */ static struct test_msg_fifo_queue test_fifo_msg_queue[FAKE_FIFO_NUM]; -void data_fifo_deinit(struct data_fifo *data_fifo) -{ - data_fifo->msgq_buffer = (char *)NULL; - data_fifo->slab_buffer = (char *)NULL; - data_fifo->elements_max = 0; - data_fifo->block_size_max = 0; - data_fifo->initialized = false; - - fifo_num = 0; -} - /* * Stubs are defined here, so that multiple *.c files can share them * without having linker issues. @@ -62,20 +53,26 @@ DEFINE_FAKE_VALUE_FUNC(int, data_fifo_pointer_last_filled_get, struct data_fifo DEFINE_FAKE_VOID_FUNC2(data_fifo_block_free, struct data_fifo *, void *); DEFINE_FAKE_VALUE_FUNC(int, data_fifo_num_used_get, struct data_fifo *, uint32_t *, uint32_t *); DEFINE_FAKE_VALUE_FUNC(int, data_fifo_empty, struct data_fifo *); +DEFINE_FAKE_VALUE_FUNC(int, data_fifo_uninit, struct data_fifo *); DEFINE_FAKE_VALUE_FUNC(int, data_fifo_init, struct data_fifo *); +void reset_fake_fifo_counter(void) +{ + fifo_num = 0; +} + +/* Custom fakes implementation */ int fake_data_fifo_pointer_first_vacant_get__succeeds(struct data_fifo *data_fifo, void **data, k_timeout_t timeout) { + int ret; struct test_slab_queue *test_fifo_slab_data = (struct test_slab_queue *)data_fifo->slab_buffer; - if (test_fifo_slab_data->head == test_fifo_slab_data->tail) { - return -EINVAL; - } + ret = k_sem_take(&test_fifo_slab_data->sem, timeout); - *data = &test_fifo_slab_data->msg[test_fifo_slab_data->tail % test_fifo_slab_data->size]; - test_fifo_slab_data->tail = (test_fifo_slab_data->tail + 1) % test_fifo_slab_data->size; + *data = &test_fifo_slab_data->msg[test_fifo_slab_data->head]; + test_fifo_slab_data->head = (test_fifo_slab_data->head + 1) % test_fifo_slab_data->size; return 0; } @@ -116,15 +113,11 @@ int fake_data_fifo_block_lock__succeeds(struct data_fifo *data_fifo, void **data struct test_msg_fifo_queue *test_fifo_msg = (struct test_msg_fifo_queue *)data_fifo->msgq_buffer; - if (((test_fifo_msg->head + 1) % test_fifo_msg->size) == test_fifo_msg->tail) { - return -EINVAL; - } + k_sem_give(&test_fifo_msg->sem); test_fifo_msg->data[test_fifo_msg->head] = *data; test_fifo_msg->head = (test_fifo_msg->head + 1) % test_fifo_msg->size; - test_fifo_msg->locked++; - return 0; } @@ -158,13 +151,12 @@ int fake_data_fifo_block_lock__put_fails(struct data_fifo *data_fifo, void **dat int fake_data_fifo_pointer_last_filled_get__succeeds(struct data_fifo *data_fifo, void **data, size_t *size, k_timeout_t timeout) { + int ret; struct audio_module_message *msg; struct test_msg_fifo_queue *test_fifo_msg = (struct test_msg_fifo_queue *)data_fifo->msgq_buffer; - if (test_fifo_msg->tail == test_fifo_msg->head) { - return -EINVAL; - } + ret = k_sem_take(&test_fifo_msg->sem, timeout); msg = (struct audio_module_message *)test_fifo_msg->data[test_fifo_msg->tail]; @@ -174,8 +166,6 @@ int fake_data_fifo_pointer_last_filled_get__succeeds(struct data_fifo *data_fifo *data = msg; *size = sizeof(struct audio_module_message); - test_fifo_msg->locked--; - return 0; } @@ -208,11 +198,8 @@ void fake_data_fifo_block_free__succeeds(struct data_fifo *data_fifo, void *data struct test_slab_queue *test_fifo_slab_data = (struct test_slab_queue *)data_fifo->slab_buffer; - if (test_fifo_slab_data->tail == test_fifo_slab_data->head) { - return; - } - - test_fifo_slab_data->head = (test_fifo_slab_data->head + 1) % test_fifo_slab_data->size; + k_sem_give(&test_fifo_slab_data->sem); + test_fifo_slab_data->tail = (test_fifo_slab_data->tail + 1) % test_fifo_slab_data->size; } int fake_data_fifo_num_used_get__succeeds(struct data_fifo *data_fifo, uint32_t *alloced_num, @@ -222,7 +209,7 @@ int fake_data_fifo_num_used_get__succeeds(struct data_fifo *data_fifo, uint32_t (struct test_msg_fifo_queue *)data_fifo->msgq_buffer; *alloced_num = test_fifo_msg->head - test_fifo_msg->tail; - *locked_num = test_fifo_msg->locked; + *locked_num = k_sem_count_get(&test_fifo_msg->sem); return 0; } @@ -247,11 +234,12 @@ int fake_data_fifo_empty__succeeds(struct data_fifo *data_fifo) test_fifo_msg->head = 0; test_fifo_msg->tail = 0; test_fifo_msg->size = FAKE_FIFO_MSG_QUEUE_SIZE; - test_fifo_msg->locked = 0; + k_sem_reset(&test_fifo_msg->sem); test_fifo_slab_data->head = 0; test_fifo_slab_data->tail = 0; test_fifo_slab_data->size = FAKE_FIFO_MSG_QUEUE_SIZE; + k_sem_init(&test_fifo_slab_data->sem, FAKE_FIFO_MSG_QUEUE_SIZE, FAKE_FIFO_MSG_QUEUE_SIZE); return 0; } @@ -284,6 +272,29 @@ int fake_data_fifo_empty__timeout_fails(struct data_fifo *data_fifo) return -EAGAIN; } +int fake_data_fifo_uninit__succeeds(struct data_fifo *data_fifo) +{ + int ret; + + if (data_fifo->initialized) { + ret = data_fifo_empty(data_fifo); + if (ret) { + return ret; + } + + data_fifo->initialized = false; + } + + return 0; +} + +int fake_data_fifo_uninit__fails(struct data_fifo *data_fifo) +{ + ARG_UNUSED(data_fifo); + + return -EINVAL; +} + int fake_data_fifo_init__succeeds(struct data_fifo *data_fifo) { struct test_msg_fifo_queue *test_fifo_msg = &test_fifo_msg_queue[fifo_num]; @@ -291,6 +302,7 @@ int fake_data_fifo_init__succeeds(struct data_fifo *data_fifo) data_fifo->msgq_buffer = (char *)test_fifo_msg; data_fifo->slab_buffer = (char *)test_fifo_slab_data; + data_fifo->elements_max = FAKE_FIFO_MSG_QUEUE_SIZE; data_fifo->block_size_max = TEST_MOD_DATA_SIZE; data_fifo->initialized = true; @@ -300,21 +312,15 @@ int fake_data_fifo_init__succeeds(struct data_fifo *data_fifo) test_fifo_msg->head = 0; test_fifo_msg->tail = 0; test_fifo_msg->size = FAKE_FIFO_MSG_QUEUE_SIZE; - test_fifo_msg->locked = 0; + k_sem_init(&test_fifo_msg->sem, 0, FAKE_FIFO_MSG_QUEUE_SIZE); test_fifo_slab_data->head = 0; test_fifo_slab_data->tail = 0; test_fifo_slab_data->size = FAKE_FIFO_MSG_QUEUE_SIZE; + k_sem_init(&test_fifo_slab_data->sem, FAKE_FIFO_MSG_QUEUE_SIZE, FAKE_FIFO_MSG_QUEUE_SIZE); for (int i = 0; i < FAKE_FIFO_MSG_QUEUE_SIZE; i++) { - if (((test_fifo_slab_data->head + 1) % test_fifo_slab_data->size) == - test_fifo_slab_data->tail) { - return -ENOMSG; - } - test_fifo_slab_data->data[test_fifo_slab_data->head] = - (void **)&test_fifo_slab_data->msg[i]; - test_fifo_slab_data->head = - (test_fifo_slab_data->head + 1) % test_fifo_slab_data->size; + test_fifo_slab_data->data[i] = (void **)&test_fifo_slab_data->msg[i]; } return 0; diff --git a/tests/subsys/audio_module/src/fakes.h b/tests/subsys/audio_module/src/fakes.h index 52bdcfc1aeae..530faf69912b 100644 --- a/tests/subsys/audio_module/src/fakes.h +++ b/tests/subsys/audio_module/src/fakes.h @@ -13,13 +13,6 @@ #include "audio_module_test_common.h" -/** - * @brief Deinitialize data FIFO structure. - * - * @param data_fifo [in/out] The data FIFO instance. - */ -void data_fifo_deinit(struct data_fifo *data_fifo); - /* Fake functions declaration. */ DECLARE_FAKE_VALUE_FUNC(int, data_fifo_pointer_first_vacant_get, struct data_fifo *, void **, k_timeout_t); @@ -29,6 +22,7 @@ DECLARE_FAKE_VALUE_FUNC(int, data_fifo_pointer_last_filled_get, struct data_fifo DECLARE_FAKE_VOID_FUNC2(data_fifo_block_free, struct data_fifo *, void *); DECLARE_FAKE_VALUE_FUNC(int, data_fifo_num_used_get, struct data_fifo *, uint32_t *, uint32_t *); DECLARE_FAKE_VALUE_FUNC(int, data_fifo_empty, struct data_fifo *); +DECLARE_FAKE_VALUE_FUNC(int, data_fifo_uninit, struct data_fifo *); DECLARE_FAKE_VALUE_FUNC(int, data_fifo_init, struct data_fifo *); /* List of fakes used by this unit tester */ @@ -40,9 +34,12 @@ DECLARE_FAKE_VALUE_FUNC(int, data_fifo_init, struct data_fifo *); FUNC(data_fifo_block_free) \ FUNC(data_fifo_num_used_get) \ FUNC(data_fifo_empty) \ + FUNC(data_fifo_uninit) \ FUNC(data_fifo_init) \ } while (0) +void reset_fake_fifo_counter(void); + int fake_data_fifo_pointer_first_vacant_get__succeeds(struct data_fifo *data_fifo, void **data, k_timeout_t timeout); int fake_data_fifo_pointer_first_vacant_get__timeout_fails(struct data_fifo *data_fifo, void **data, @@ -71,6 +68,8 @@ int fake_data_fifo_empty__count_fails(struct data_fifo *data_fifo); int fake_data_fifo_empty__no_wait_fails(struct data_fifo *data_fifo); int fake_data_fifo_empty__slab_init_fails(struct data_fifo *data_fifo); int fake_data_fifo_empty__timeout_fails(struct data_fifo *data_fifo); +int fake_data_fifo_uninit__succeeds(struct data_fifo *data_fifo); +int fake_data_fifo_uninit__fails(struct data_fifo *data_fifo); int fake_data_fifo_init__succeeds(struct data_fifo *data_fifo); int fake_data_fifo_init__fails(struct data_fifo *data_fifo); diff --git a/tests/subsys/audio_module/src/functional_test.c b/tests/subsys/audio_module/src/functional_test.c index fa6e459a9061..0b68ead657f1 100644 --- a/tests/subsys/audio_module/src/functional_test.c +++ b/tests/subsys/audio_module/src/functional_test.c @@ -45,9 +45,7 @@ static struct audio_module_parameters mod_parameters = { .data_slab = &data_slab, .data_size = TEST_MOD_DATA_SIZE}}; struct audio_module_parameters test_mod_parameters; -static struct audio_module_handle handle; static struct mod_context *handle_context; -static struct data_fifo mod_fifo_tx, mod_fifo_rx; /** * @brief Set the minimum for a handle. @@ -217,10 +215,12 @@ static void test_close(const struct audio_module_functions *test_fnct, enum audio_module_state test_state) { int ret; - int empty_call_count = 0; char *test_inst_name = "TEST instance 1"; struct audio_module_description test_mod_description; struct audio_module_functions test_mod_functions; + struct data_fifo fifo_tx = {0}; + struct data_fifo fifo_rx = {0}; + struct audio_module_handle handle; /* Register resets */ DO_FOREACH_FAKE(RESET_FAKE); @@ -253,21 +253,15 @@ static void test_close(const struct audio_module_functions *test_fnct, data_fifo_empty_fake.custom_fake = fake_data_fifo_empty__succeeds; if (fifo_rx_set) { - data_fifo_deinit(&mod_fifo_rx); - data_fifo_init(&mod_fifo_rx); - handle.thread.msg_rx = &mod_fifo_rx; - - empty_call_count++; + data_fifo_init(&fifo_rx); + handle.thread.msg_rx = &fifo_rx; } else { handle.thread.msg_rx = NULL; } if (fifo_tx_set) { - data_fifo_deinit(&mod_fifo_tx); - data_fifo_init(&mod_fifo_tx); - handle.thread.msg_tx = &mod_fifo_tx; - - empty_call_count++; + data_fifo_init(&fifo_tx); + handle.thread.msg_tx = &fifo_tx; } else { handle.thread.msg_tx = NULL; } @@ -279,9 +273,6 @@ static void test_close(const struct audio_module_functions *test_fnct, ret = audio_module_close(&handle); zassert_equal(ret, 0, "Close function did not return successfully: ret %d", ret); - zassert_equal(data_fifo_empty_fake.call_count, empty_call_count, - "Failed close, data FIFO empty called %d times", - data_fifo_empty_fake.call_count); zassert_mem_equal(&mod_description, &test_mod_description, sizeof(struct audio_module_description), "Failed close, modified the modules description"); @@ -310,6 +301,9 @@ static void test_open(enum audio_module_type test_type, bool fifo_rx_set, bool f { int ret; char *test_inst_name = "TEST instance 1"; + struct data_fifo fifo_tx = {0}; + struct data_fifo fifo_rx = {0}; + struct audio_module_handle handle; /* Fake internal empty data FIFO success */ data_fifo_init_fake.custom_fake = fake_data_fifo_init__succeeds; @@ -319,17 +313,15 @@ static void test_open(enum audio_module_type test_type, bool fifo_rx_set, bool f test_context_set(&test_mod_context, &mod_config); if (fifo_rx_set) { - data_fifo_deinit(&mod_fifo_rx); - data_fifo_init(&mod_fifo_rx); - mod_parameters.thread.msg_rx = &mod_fifo_rx; + data_fifo_init(&fifo_rx); + mod_parameters.thread.msg_rx = &fifo_rx; } else { mod_parameters.thread.msg_rx = NULL; } if (fifo_tx_set) { - data_fifo_deinit(&mod_fifo_tx); - data_fifo_init(&mod_fifo_tx); - mod_parameters.thread.msg_tx = &mod_fifo_tx; + data_fifo_init(&fifo_tx); + mod_parameters.thread.msg_tx = &fifo_tx; } else { mod_parameters.thread.msg_tx = NULL; } @@ -459,6 +451,7 @@ static void test_start_stop(bool start, const struct audio_module_functions *tes enum audio_module_state return_state, int ret_expected) { int ret; + struct audio_module_handle handle; mod_description.functions = test_fnct; test_initialize_handle(&handle, &mod_description, &mod_context, NULL); @@ -562,6 +555,7 @@ ZTEST(suite_audio_module_functional, test_names_get_fnct) int ret; char *base_name; char instance_name[CONFIG_AUDIO_MODULE_NAME_SIZE] = {0}; + struct audio_module_handle handle; char *test_base_name_empty = ""; char *test_base_name_long = "Test base name that is longer than the size of CONFIG_AUDIO_MODULE_NAME_SIZE"; @@ -629,6 +623,7 @@ ZTEST(suite_audio_module_functional, test_names_get_fnct) ZTEST(suite_audio_module_functional, test_reconfigure_fnct) { int ret; + struct audio_module_handle handle; mod_description.functions = &ft_pop; test_initialize_handle(&handle, &mod_description, &mod_context, &mod_config); @@ -659,6 +654,7 @@ ZTEST(suite_audio_module_functional, test_reconfigure_fnct) ZTEST(suite_audio_module_functional, test_configuration_get_fnct) { int ret; + struct audio_module_handle handle; mod_description.functions = &ft_pop; test_initialize_handle(&handle, &mod_description, &mod_context, &mod_config); @@ -919,11 +915,15 @@ ZTEST(suite_audio_module_functional, test_data_tx_fnct) char test_data[TEST_MOD_DATA_SIZE]; struct audio_data audio_data = {0}; struct audio_module_message *msg_rx; + struct data_fifo fifo_rx; + struct audio_module_handle handle; test_context_set(&mod_context, &mod_config); /* Fake internal empty data FIFO success */ data_fifo_init_fake.custom_fake = fake_data_fifo_init__succeeds; + data_fifo_uninit_fake.custom_fake = fake_data_fifo_uninit__succeeds; + data_fifo_empty_fake.custom_fake = fake_data_fifo_empty__succeeds; data_fifo_pointer_first_vacant_get_fake.custom_fake = fake_data_fifo_pointer_first_vacant_get__succeeds; data_fifo_block_lock_fake.custom_fake = fake_data_fifo_block_lock__succeeds; @@ -931,13 +931,12 @@ ZTEST(suite_audio_module_functional, test_data_tx_fnct) fake_data_fifo_pointer_last_filled_get__succeeds; data_fifo_block_free_fake.custom_fake = fake_data_fifo_block_free__succeeds; - data_fifo_deinit(&mod_fifo_rx); - - data_fifo_init(&mod_fifo_rx); + data_fifo_uninit(&fifo_rx); + data_fifo_init(&fifo_rx); memcpy(&handle.name, test_inst_name, sizeof(*test_inst_name)); handle.description = &mod_description; - handle.thread.msg_rx = &mod_fifo_rx; + handle.thread.msg_rx = &fifo_rx; handle.thread.msg_tx = NULL; handle.thread.data_slab = &data_slab; handle.thread.data_size = TEST_MOD_DATA_SIZE; @@ -948,22 +947,39 @@ ZTEST(suite_audio_module_functional, test_data_tx_fnct) test_data[i] = TEST_MOD_DATA_SIZE - i; } - audio_data.data = &test_data[0]; + audio_data.data = NULL; audio_data.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_tx(&handle, &audio_data, NULL); zassert_equal(ret, 0, "Data TX function did not return successfully: ret %d", ret); - ret = data_fifo_pointer_last_filled_get(&mod_fifo_rx, (void **)&msg_rx, &size, K_NO_WAIT); + ret = data_fifo_pointer_last_filled_get(&fifo_rx, (void **)&msg_rx, &size, K_NO_WAIT); zassert_equal(ret, 0, "Data TX function did not return 0: ret %d", 0, ret); - zassert_mem_equal(msg_rx->audio_data.data, &test_data[0], TEST_MOD_DATA_SIZE, - "Failed open, module contexts differ"); + + audio_data.data = test_data; + audio_data.data_size = 0; + + ret = audio_module_data_tx(&handle, &audio_data, NULL); + zassert_equal(ret, 0, "Data TX function did not return successfully: ret %d", ret); + + data_fifo_empty(&fifo_rx); + + audio_data.data = test_data; + audio_data.data_size = TEST_MOD_DATA_SIZE; + + ret = audio_module_data_tx(&handle, &audio_data, NULL); + zassert_equal(ret, 0, "Data TX function did not return successfully: ret %d", ret); + + ret = data_fifo_pointer_last_filled_get(&fifo_rx, (void **)&msg_rx, &size, K_NO_WAIT); + zassert_equal(ret, 0, "Data TX function did not return 0: ret %d", 0, ret); + zassert_mem_equal(msg_rx->audio_data.data, test_data, TEST_MOD_DATA_SIZE, + "Failed Data TX, data differs"); zassert_equal(msg_rx->audio_data.data_size, TEST_MOD_DATA_SIZE, "Failed Data TX function, data sizes differs"); - zassert_equal(data_fifo_pointer_first_vacant_get_fake.call_count, 1, + zassert_equal(data_fifo_pointer_first_vacant_get_fake.call_count, 3, "Data TX failed to get item, data FIFO get called %d times", data_fifo_pointer_first_vacant_get_fake.call_count); - zassert_equal(data_fifo_block_lock_fake.call_count, 1, + zassert_equal(data_fifo_block_lock_fake.call_count, 3, "Failed to send item, data FIFO send called %d times", data_fifo_pointer_first_vacant_get_fake.call_count); } @@ -974,14 +990,17 @@ ZTEST(suite_audio_module_functional, test_data_rx_fnct) char *test_inst_name = "TEST instance 1"; char test_data[TEST_MOD_DATA_SIZE]; char data[TEST_MOD_DATA_SIZE] = {0}; - struct audio_data audio_data_in; struct audio_data audio_data_out = {0}; struct audio_module_message *data_msg_tx; + struct data_fifo fifo_tx = {0}; + struct audio_module_handle handle; test_context_set(&mod_context, &mod_config); /* Fake internal empty data FIFO success */ data_fifo_init_fake.custom_fake = fake_data_fifo_init__succeeds; + data_fifo_uninit_fake.custom_fake = fake_data_fifo_uninit__succeeds; + data_fifo_empty_fake.custom_fake = fake_data_fifo_empty__succeeds; data_fifo_pointer_first_vacant_get_fake.custom_fake = fake_data_fifo_pointer_first_vacant_get__succeeds; data_fifo_block_lock_fake.custom_fake = fake_data_fifo_block_lock__succeeds; @@ -989,49 +1008,86 @@ ZTEST(suite_audio_module_functional, test_data_rx_fnct) fake_data_fifo_pointer_last_filled_get__succeeds; data_fifo_block_free_fake.custom_fake = fake_data_fifo_block_free__succeeds; - data_fifo_deinit(&mod_fifo_tx); - - data_fifo_init(&mod_fifo_tx); + data_fifo_init(&fifo_tx); memcpy(&handle.name, test_inst_name, sizeof(*test_inst_name)); handle.description = &mod_description; handle.thread.msg_rx = NULL; - handle.thread.msg_tx = &mod_fifo_tx; + handle.thread.msg_tx = &fifo_tx; handle.thread.data_slab = &data_slab; handle.thread.data_size = TEST_MOD_DATA_SIZE; handle.state = AUDIO_MODULE_STATE_RUNNING; handle.context = (struct audio_module_context *)&mod_context; - ret = data_fifo_pointer_first_vacant_get(handle.thread.msg_tx, (void **)&data_msg_tx, - K_NO_WAIT); /* fill data */ for (int i = 0; i < TEST_MOD_DATA_SIZE; i++) { test_data[i] = TEST_MOD_DATA_SIZE - i; } - audio_data_in.data = &test_data[0]; - audio_data_in.data_size = TEST_MOD_DATA_SIZE; + ret = data_fifo_pointer_first_vacant_get(handle.thread.msg_tx, (void **)&data_msg_tx, + K_NO_WAIT); + zassert_equal(ret, 0, "FIFO get function did not return successfully: ret %d", ret); + + data_msg_tx->audio_data.data = test_data; + data_msg_tx->audio_data.data_size = TEST_MOD_DATA_SIZE; + data_msg_tx->tx_handle = NULL; + data_msg_tx->response_cb = NULL; + + ret = data_fifo_block_lock(handle.thread.msg_tx, (void **)&data_msg_tx, + sizeof(struct audio_module_message)); + zassert_equal(ret, 0, "FIFO lock function did not return successfully: ret %d", ret); + + audio_data_out.data = NULL; + audio_data_out.data_size = TEST_MOD_DATA_SIZE; + + ret = audio_module_data_rx(&handle, &audio_data_out, K_NO_WAIT); + zassert_equal(ret, 0, "Data RX function did not return successfully: ret %d", ret); + + ret = data_fifo_pointer_first_vacant_get(handle.thread.msg_tx, (void **)&data_msg_tx, + K_NO_WAIT); + zassert_equal(ret, 0, "FIFO get function did not return successfully: ret %d", ret); + + data_msg_tx->audio_data.data = test_data; + data_msg_tx->audio_data.data_size = TEST_MOD_DATA_SIZE; + data_msg_tx->tx_handle = NULL; + data_msg_tx->response_cb = NULL; + + ret = data_fifo_block_lock(handle.thread.msg_tx, (void **)&data_msg_tx, + sizeof(struct audio_module_message)); + zassert_equal(ret, 0, "FIFO lock function did not return successfully: ret %d", ret); + + audio_data_out.data = data; + audio_data_out.data_size = 0; + + ret = audio_module_data_rx(&handle, &audio_data_out, K_NO_WAIT); + zassert_equal(ret, 0, "Data RX function did not return successfully: ret %d", ret); + + ret = data_fifo_pointer_first_vacant_get(handle.thread.msg_tx, (void **)&data_msg_tx, + K_NO_WAIT); + zassert_equal(ret, 0, "FIFO get function did not return successfully: ret %d", ret); - memcpy(&data_msg_tx->audio_data, &audio_data_in, sizeof(struct audio_data)); + data_msg_tx->audio_data.data = test_data; + data_msg_tx->audio_data.data_size = TEST_MOD_DATA_SIZE; data_msg_tx->tx_handle = NULL; data_msg_tx->response_cb = NULL; ret = data_fifo_block_lock(handle.thread.msg_tx, (void **)&data_msg_tx, sizeof(struct audio_module_message)); + zassert_equal(ret, 0, "FIFO lock function did not return successfully: ret %d", ret); - audio_data_out.data = &data[0]; + audio_data_out.data = data; audio_data_out.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_rx(&handle, &audio_data_out, K_NO_WAIT); zassert_equal(ret, 0, "Data RX function did not return successfully: ret %d", ret); - zassert_mem_equal(&test_data[0], audio_data_out.data, TEST_MOD_DATA_SIZE, + zassert_mem_equal(test_data, audio_data_out.data, TEST_MOD_DATA_SIZE, "Failed Data RX function, data differs"); - zassert_equal(audio_data_in.data_size, audio_data_out.data_size, + zassert_equal(audio_data_out.data_size, TEST_MOD_DATA_SIZE, "Failed Data RX function, data sizes differs"); - zassert_equal(data_fifo_pointer_last_filled_get_fake.call_count, 1, + zassert_equal(data_fifo_pointer_last_filled_get_fake.call_count, 3, "Data RX function failed to get item, data FIFO get called %d times", data_fifo_pointer_last_filled_get_fake.call_count); - zassert_equal(data_fifo_block_free_fake.call_count, 1, + zassert_equal(data_fifo_block_free_fake.call_count, 3, "Data RX function failed to free item, data FIFO free called %d times", data_fifo_block_free_fake.call_count); } diff --git a/tests/subsys/audio_module/src/main.c b/tests/subsys/audio_module/src/main.c index 72e80831e58e..abd696bfb05e 100644 --- a/tests/subsys/audio_module/src/main.c +++ b/tests/subsys/audio_module/src/main.c @@ -7,7 +7,6 @@ #include #include #include - #include "fakes.h" /* This function runs before each test */ @@ -22,5 +21,5 @@ static void run_before(void *fixture) FFF_RESET_HISTORY(); } -ZTEST_SUITE(suite_audio_module_bad_param, NULL, NULL, NULL, NULL, NULL); +ZTEST_SUITE(suite_audio_module_bad_param, NULL, NULL, run_before, NULL, NULL); ZTEST_SUITE(suite_audio_module_functional, NULL, NULL, run_before, NULL, NULL); diff --git a/tests/subsys/audio_module/testcase.yaml b/tests/subsys/audio_module/testcase.yaml index 35ad5da21c38..d4dc1b9d13f3 100644 --- a/tests/subsys/audio_module/testcase.yaml +++ b/tests/subsys/audio_module/testcase.yaml @@ -1,7 +1,7 @@ tests: nrf5340_audio.audio_module_test: sysbuild: true - platform_allow: qemu_cortex_m3 nrf5340dk/nrf5340/cpuapp + platform_allow: qemu_cortex_m3 integration_platforms: - qemu_cortex_m3 - nrf5340dk/nrf5340/cpuapp diff --git a/tests/subsys/audio_modules/audio_module_template/CMakeLists.txt b/tests/subsys/audio_modules/audio_module_template/CMakeLists.txt new file mode 100644 index 000000000000..18cf31748ead --- /dev/null +++ b/tests/subsys/audio_modules/audio_module_template/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# Copyright (c) 20234 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project("Audio module Template") + +target_sources(app PRIVATE + src/main.c + src/template_test.c +) + +target_include_directories(app PRIVATE ${ZEPHYR_NRF_MODULE_DIR}/subsys/audio_modules/audio_module_template) diff --git a/tests/subsys/audio_modules/audio_module_template/prj.conf b/tests/subsys/audio_modules/audio_module_template/prj.conf new file mode 100644 index 000000000000..5aa1308f4a9e --- /dev/null +++ b/tests/subsys/audio_modules/audio_module_template/prj.conf @@ -0,0 +1,17 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +CONFIG_ZTEST=y +CONFIG_ZTEST_STACK_SIZE=8196 +CONFIG_IRQ_OFFLOAD=y +CONFIG_DATA_FIFO=y +CONFIG_AUDIO_MODULE=y +CONFIG_AUDIO_MODULE_TEMPLATE=y + +# The large stack size can be optimized +CONFIG_MAIN_STACK_SIZE=16000 + +CONFIG_STACK_SENTINEL=y diff --git a/tests/subsys/audio_modules/audio_module_template/src/main.c b/tests/subsys/audio_modules/audio_module_template/src/main.c new file mode 100644 index 000000000000..fe0369f7b663 --- /dev/null +++ b/tests/subsys/audio_modules/audio_module_template/src/main.c @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include + +ZTEST_SUITE(suite_audio_module_template, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/audio_modules/audio_module_template/src/template_test.c b/tests/subsys/audio_modules/audio_module_template/src/template_test.c new file mode 100644 index 000000000000..982f07d6cbb6 --- /dev/null +++ b/tests/subsys/audio_modules/audio_module_template/src/template_test.c @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include + +#include "audio_module.h" +#include "audio_module_template.h" + +/* Define a timeout to prevent system locking */ +#define TEST_TX_RX_TIMEOUT_US (K_FOREVER) + +#define CONFIG_TEXT "Template config" +#define RECONFIG_TEXT "Template reconfig" + +#define TEST_MSG_QUEUE_SIZE (4) +#define TEST_MOD_THREAD_STACK_SIZE (2048) +#define TEST_MOD_THREAD_PRIORITY (4) +#define TEST_CONNECTIONS_NUM (5) +#define TEST_MODULES_NUM (TEST_CONNECTIONS_NUM - 1) +#define TEST_MOD_DATA_SIZE (40) +#define TEST_MSG_SIZE (sizeof(struct audio_module_message)) +#define TEST_AUDIO_DATA_ITEMS_NUM (20) + +struct mod_config { + int test_int1; + int test_int2; + int test_int3; + int test_int4; +}; + +struct mod_context { + const char *test_string; + uint32_t test_uint32; + + struct mod_config config; +}; + +const char *test_instance_name = "Test instance"; +struct audio_metadata test_metadata = {.data_coding = LC3, + .data_len_us = 10000, + .sample_rate_hz = 48000, + .bits_per_sample = 16, + .carried_bits_pr_sample = 16, + .locations = 0x00000003, + .reference_ts_us = 0, + .data_rx_ts_us = 0, + .bad_data = false}; + +K_THREAD_STACK_ARRAY_DEFINE(mod_temp_stack, TEST_MODULES_NUM, TEST_MOD_THREAD_STACK_SIZE); +DATA_FIFO_DEFINE(msg_fifo_tx, TEST_MSG_QUEUE_SIZE, TEST_MSG_SIZE); +DATA_FIFO_DEFINE(msg_fifo_rx, TEST_MSG_QUEUE_SIZE, TEST_MSG_SIZE); +DATA_FIFO_DEFINE(msg_fifo_tx1, TEST_MSG_QUEUE_SIZE, TEST_MSG_SIZE); +DATA_FIFO_DEFINE(msg_fifo_rx1, TEST_MSG_QUEUE_SIZE, TEST_MSG_SIZE); +DATA_FIFO_DEFINE(msg_fifo_tx2, TEST_MSG_QUEUE_SIZE, TEST_MSG_SIZE); +DATA_FIFO_DEFINE(msg_fifo_rx2, TEST_MSG_QUEUE_SIZE, TEST_MSG_SIZE); +DATA_FIFO_DEFINE(msg_fifo_tx3, TEST_MSG_QUEUE_SIZE, TEST_MSG_SIZE); +DATA_FIFO_DEFINE(msg_fifo_rx3, TEST_MSG_QUEUE_SIZE, TEST_MSG_SIZE); +K_MEM_SLAB_DEFINE(mod_data_slab, TEST_MOD_DATA_SIZE, TEST_MSG_QUEUE_SIZE, 4); + +struct data_fifo *msg_fifo_tx_array[TEST_MODULES_NUM] = {&msg_fifo_tx, &msg_fifo_tx1, &msg_fifo_tx2, + &msg_fifo_tx3}; +struct data_fifo *msg_fifo_rx_array[TEST_MODULES_NUM] = {&msg_fifo_rx, &msg_fifo_rx1, &msg_fifo_rx2, + &msg_fifo_rx3}; + +ZTEST(suite_audio_module_template, test_module_template) +{ + int ret; + int i; + char *base_name, instance_name[CONFIG_AUDIO_MODULE_NAME_SIZE]; + + struct audio_data audio_data_tx; + struct audio_data audio_data_rx; + + struct audio_module_parameters mod_parameters; + + struct audio_module_template_configuration configuration = { + .sample_rate_hz = 48000, .bit_depth = 12345, .some_text = CONFIG_TEXT}; + struct audio_module_template_configuration reconfiguration = { + .sample_rate_hz = 16000, .bit_depth = 54321, .some_text = RECONFIG_TEXT}; + struct audio_module_template_configuration return_configuration; + + struct audio_module_template_context context = {0}; + + uint8_t test_data_in[TEST_MOD_DATA_SIZE * TEST_AUDIO_DATA_ITEMS_NUM]; + uint8_t test_data_out[TEST_MOD_DATA_SIZE * TEST_AUDIO_DATA_ITEMS_NUM]; + + struct audio_module_handle handle; + + data_fifo_init(&msg_fifo_rx); + data_fifo_init(&msg_fifo_tx); + + mod_parameters.description = audio_module_template_description; + mod_parameters.thread.stack = mod_temp_stack[0]; + mod_parameters.thread.stack_size = TEST_MOD_THREAD_STACK_SIZE; + mod_parameters.thread.priority = TEST_MOD_THREAD_PRIORITY; + mod_parameters.thread.data_slab = &mod_data_slab; + mod_parameters.thread.data_size = TEST_MOD_DATA_SIZE; + mod_parameters.thread.msg_rx = &msg_fifo_rx; + mod_parameters.thread.msg_tx = &msg_fifo_tx; + + ret = audio_module_open( + &mod_parameters, (struct audio_module_configuration const *const)&configuration, + test_instance_name, (struct audio_module_context *)&context, &handle); + zassert_equal(ret, 0, "Open function did not return successfully (0): ret %d", ret); + + { + struct audio_module_template_context *ctx = + (struct audio_module_template_context *)handle.context; + struct audio_module_template_configuration *test_config = &ctx->config; + + zassert_equal(test_config->bit_depth, configuration.bit_depth, + "Failed to configure module in the open function"); + zassert_equal(test_config->sample_rate_hz, configuration.sample_rate_hz, + "Failed to configure module in the open function"); + zassert_mem_equal(test_config->some_text, configuration.some_text, + sizeof(CONFIG_TEXT), + "Failed to configure module in the open function"); + } + + zassert_equal_ptr(handle.description->name, audio_module_template_description->name, + "Failed open for names, base name should be %s, but is %s", + audio_module_template_description->name, handle.description->name); + zassert_mem_equal(&handle.name[0], test_instance_name, strlen(test_instance_name), + "Failed open for names, instance name should be %s, but is %s", + test_instance_name, handle.name); + zassert_equal(handle.state, AUDIO_MODULE_STATE_CONFIGURED, + "Not in configured state after call to open the audio module"); + + ret = audio_module_names_get(&handle, &base_name, &instance_name[0]); + zassert_equal(ret, 0, "Get names function did not return successfully (0): ret %d", ret); + zassert_mem_equal(base_name, audio_module_template_description->name, + strlen(audio_module_template_description->name), + "Failed get names, base name should be %s, but is %s", + audio_module_template_description->name, base_name); + zassert_mem_equal(&instance_name[0], test_instance_name, strlen(test_instance_name), + "Failed get names, instance name should be %s, but is %s", handle.name, + &instance_name[0]); + + ret = audio_module_configuration_get( + &handle, (struct audio_module_configuration *)&return_configuration); + zassert_equal(ret, 0, "Configuration get function did not return successfully (0): ret %d", + ret); + zassert_equal(return_configuration.bit_depth, configuration.bit_depth, + "Failed to get configuration"); + zassert_equal(return_configuration.sample_rate_hz, configuration.sample_rate_hz, + "Failed to get configuration"); + zassert_mem_equal(return_configuration.some_text, configuration.some_text, + sizeof(CONFIG_TEXT), "Failed to get configuration"); + + ret = audio_module_connect(&handle, NULL, true); + zassert_equal(ret, 0, "Connect function did not return successfully (0): ret %d", ret); + zassert_equal(handle.use_tx_queue, 1, "Connect queue size is not %d, but is %d", 1, + handle.use_tx_queue); + + ret = audio_module_start(&handle); + zassert_equal(ret, 0, "Start function did not return successfully (0): ret %d", ret); + zassert_equal(handle.state, AUDIO_MODULE_STATE_RUNNING, + "Not in running state after call to start the audio module"); + + for (i = 0; i < TEST_AUDIO_DATA_ITEMS_NUM; i++) { + audio_data_tx.data = (void *)&test_data_in[i * TEST_MOD_DATA_SIZE]; + audio_data_tx.data_size = TEST_MOD_DATA_SIZE; + memcpy(&audio_data_tx.meta, &test_metadata, sizeof(struct audio_metadata)); + + audio_data_rx.data = (void *)&test_data_out[i * TEST_MOD_DATA_SIZE]; + audio_data_rx.data_size = TEST_MOD_DATA_SIZE; + + ret = audio_module_data_tx_rx(&handle, &handle, &audio_data_tx, &audio_data_rx, + TEST_TX_RX_TIMEOUT_US); + zassert_equal(ret, 0, "Data TX-RX function did not return successfully (0): ret %d", + ret); + zassert_mem_equal(audio_data_tx.data, audio_data_rx.data, TEST_MOD_DATA_SIZE, + "Failed to process data"); + zassert_equal(audio_data_tx.data_size, audio_data_rx.data_size, + "Failed to process data, sizes differ"); + zassert_mem_equal(&audio_data_tx.meta, &audio_data_rx.meta, + sizeof(struct audio_metadata), + "Failed to process data, meta data differs"); + + if (i == TEST_AUDIO_DATA_ITEMS_NUM / 2) { + ret = audio_module_stop(&handle); + zassert_equal(ret, 0, + "Stop function did not return successfully (0): ret %d", ret); + + ret = audio_module_reconfigure( + &handle, + (const struct audio_module_configuration *const)&reconfiguration); + zassert_equal( + ret, 0, + "Reconfigure function did not return successfully (0): ret %d", + ret); + zassert_equal(reconfiguration.bit_depth, reconfiguration.bit_depth, + "Failed to reconfigure module"); + zassert_equal(reconfiguration.sample_rate_hz, + reconfiguration.sample_rate_hz, + "Failed to reconfigure module"); + zassert_mem_equal(reconfiguration.some_text, reconfiguration.some_text, + sizeof(RECONFIG_TEXT), "Failed to reconfigure module"); + + ret = audio_module_start(&handle); + zassert_equal(ret, 0, + "Start function did not return successfully (0): ret %d", + ret); + zassert_equal(handle.state, AUDIO_MODULE_STATE_RUNNING, + "Not in running state after call to start the audio module"); + } + } + + ret = audio_module_disconnect(&handle, NULL, true); + zassert_equal(ret, 0, "Disconnect function did not return successfully (0): ret %d", ret); + zassert_equal(handle.use_tx_queue, 0, "Disconnect queue size is not %d, but is %d", 0, + handle.use_tx_queue); + + ret = audio_module_stop(&handle); + zassert_equal(ret, 0, "Stop function did not return successfully (0): ret %d", ret); + zassert_equal(handle.state, AUDIO_MODULE_STATE_STOPPED, + "Not in stopped state after call to stop the audio module"); + + ret = audio_module_close(&handle); + zassert_equal(ret, 0, "Close function did not return successfully (0): ret %d", ret); +} + +ZTEST(suite_audio_module_template, test_module_template_stream) +{ + int ret; + int i; + char inst_name[CONFIG_AUDIO_MODULE_NAME_SIZE]; + + struct audio_data audio_data_tx; + struct audio_data audio_data_rx; + + struct audio_module_parameters mod_parameters; + + struct audio_module_template_configuration configuration = { + .sample_rate_hz = 48000, .bit_depth = 12345, .some_text = CONFIG_TEXT}; + + struct audio_module_template_context context = {0}; + + uint8_t test_data_in[TEST_MOD_DATA_SIZE * TEST_AUDIO_DATA_ITEMS_NUM]; + uint8_t test_data_out[TEST_MOD_DATA_SIZE * TEST_AUDIO_DATA_ITEMS_NUM]; + + struct audio_module_handle handle[TEST_MODULES_NUM]; + + for (i = 0; i < TEST_MODULES_NUM; i++) { + + memset(&handle[i], 0, sizeof(struct audio_module_handle)); + + data_fifo_init(msg_fifo_rx_array[i]); + data_fifo_init(msg_fifo_tx_array[i]); + + mod_parameters.description = audio_module_template_description; + mod_parameters.thread.stack = mod_temp_stack[i]; + mod_parameters.thread.stack_size = TEST_MOD_THREAD_STACK_SIZE; + mod_parameters.thread.priority = TEST_MOD_THREAD_PRIORITY; + mod_parameters.thread.data_slab = &mod_data_slab; + mod_parameters.thread.data_size = TEST_MOD_DATA_SIZE; + mod_parameters.thread.msg_rx = msg_fifo_rx_array[i]; + mod_parameters.thread.msg_tx = msg_fifo_tx_array[i]; + + ret = audio_module_open( + &mod_parameters, + (const struct audio_module_configuration *const)&configuration, + &inst_name[0], (struct audio_module_context *)&context, &handle[i]); + zassert_equal(ret, 0, "Open function did not return successfully (0): ret %d", ret); + } + + for (i = 1; i < TEST_MODULES_NUM; i++) { + ret = audio_module_connect(&handle[i - 1], &handle[i], false); + zassert_equal(ret, 0, "Connect function did not return successfully (0): ret %d", + ret); + } + + ret = audio_module_connect(&handle[TEST_MODULES_NUM - 1], NULL, true); + zassert_equal(ret, 0, "Connect function did not return successfully (0): ret %d", ret); + + for (i = 0; i < TEST_MODULES_NUM; i++) { + ret = audio_module_start(&handle[i]); + zassert_equal(ret, 0, "Start function did not return successfully (0): ret %d", + ret); + } + + for (i = 0; i < TEST_AUDIO_DATA_ITEMS_NUM; i++) { + audio_data_tx.data = (void *)&test_data_in[i * TEST_MOD_DATA_SIZE]; + audio_data_tx.data_size = TEST_MOD_DATA_SIZE; + memcpy(&audio_data_tx.meta, &test_metadata, sizeof(struct audio_metadata)); + + audio_data_rx.data = (void *)&test_data_out[i * TEST_MOD_DATA_SIZE]; + audio_data_rx.data_size = TEST_MOD_DATA_SIZE; + + ret = audio_module_data_tx_rx(&handle[0], &handle[TEST_MODULES_NUM - 1], + &audio_data_tx, &audio_data_rx, + TEST_TX_RX_TIMEOUT_US); + zassert_equal(ret, 0, "Data TX-RX function did not return successfully (0): ret %d", + ret); + zassert_mem_equal(audio_data_tx.data, audio_data_rx.data, TEST_MOD_DATA_SIZE, + "Failed to process data"); + zassert_equal(audio_data_tx.data_size, audio_data_rx.data_size, + "Failed to process data, sizes differ"); + zassert_mem_equal(&audio_data_tx.meta, &audio_data_rx.meta, + sizeof(struct audio_metadata), + "Failed to process data, meta data differs"); + } + + for (i = 1; i < TEST_MODULES_NUM; i++) { + ret = audio_module_stop(&handle[i]); + zassert_equal(ret, 0, "Stop function did not return successfully (0): ret %d", ret); + + ret = audio_module_close(&handle[i]); + zassert_equal(ret, 0, "Close function did not return successfully (0): ret %d", + ret); + } +} diff --git a/tests/subsys/audio_modules/audio_module_template/testcase.yaml b/tests/subsys/audio_modules/audio_module_template/testcase.yaml new file mode 100644 index 000000000000..75f6f3f693e4 --- /dev/null +++ b/tests/subsys/audio_modules/audio_module_template/testcase.yaml @@ -0,0 +1,7 @@ +tests: + nrf5340_audio.audio_module_template: + sysbuild: true + platform_allow: qemu_cortex_m3 + integration_platforms: + - qemu_cortex_m3 + tags: audio_module audio_module_template nrf5340_audio_unit_tests sysbuild