/** * Copyright (c) 2011 - 2020, Nordic Semiconductor ASA * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form, except as embedded into a Nordic * Semiconductor ASA integrated circuit in a product or a software update for * such product, must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. Neither the name of Nordic Semiconductor ASA nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * 4. This software, with or without modification, must only be used with a * Nordic Semiconductor ASA integrated circuit. * * 5. Any software provided in binary form under this license must not be reverse * engineered, decompiled, modified and/or disassembled. * * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef NRF_ATFIFO_H__ #define NRF_ATFIFO_H__ #include #include #include "sdk_config.h" #include "nordic_common.h" #include "nrf_assert.h" #include "sdk_errors.h" #include "nrf_log_instance.h" #ifdef __cplusplus extern "C" { #endif /** * @defgroup nrf_atfifo Atomic FIFO * @ingroup app_common * * @brief @tagAPI52 FIFO implementation that allows for making atomic transactions without * locking interrupts. * * @details There are two types of functions to prepare the FIFO writing: * - Single function for simple access: * @code * if (NRF_SUCCESS != nrf_atfifo_simple_put(my_fifo, &data, NULL)) * { * // Error handling * } * @endcode * - Function pair to limit data copying: * @code * struct point3d * { * int x, y, z; * }point3d_t; * nrf_atfifo_context_t context; * point3d_t * point; * * if (NULL != (point = nrf_atfifo_item_alloc(my_fifo, &context))) * { * point->x = a; * point->y = b; * point->z = c; * if (nrf_atfifo_item_put(my_fifo, &context)) * { * // Send information to the rest of the system * // that there is new data in the FIFO available for reading. * } * } * else * { * // Error handling * } * * @endcode * @note * This atomic FIFO implementation requires that the operation that is * opened last is finished (committed/flushed) first. * This is typical for operations performed from the interrupt runtime * when the other operation is performed from the main thread. * * This implementation does not support typical multithreading operating system * access where operations can be started and finished in totally unrelated order. * * @{ */ /** * @brief Read and write position structure. * * A structure that holds the read and write position used by the FIFO head and tail. */ typedef struct nrf_atfifo_postag_pos_s { uint16_t wr; //!< First free space to write the data uint16_t rd; //!< A place after the last data to read }nrf_atfifo_postag_pos_t; /** * @brief End data index tag. * * A tag used to mark the end of data. * To properly realize atomic data committing, the whole variable has to be * accessed atomically. */ typedef union nrf_atfifo_postag_u { uint32_t tag; //!< Whole tag, used for atomic, 32-bit access nrf_atfifo_postag_pos_t pos; //!< Structure that holds reading and writing position separately }nrf_atfifo_postag_t; /** * @brief The FIFO instance. * * The instance of atomic FIFO. * Used with all FIFO functions. */ typedef struct nrf_atfifo_s { void * p_buf; //!< Pointer to the data buffer nrf_atfifo_postag_t tail; //!< Read and write tail position tag nrf_atfifo_postag_t head; //!< Read and write head position tag uint16_t buf_size; //!< FIFO size in number of bytes (has to be divisible by @c item_size) uint16_t item_size; //!< Size of a single FIFO item NRF_LOG_INSTANCE_PTR_DECLARE(p_log) //!< Pointer to instance of the logger object (Conditionally compiled). }nrf_atfifo_t; /** * @brief FIFO write operation item context. * * Context structure used to mark an allocated space in FIFO that is ready for put. * All the data required to properly put allocated and written data. */ typedef struct nrf_atfifo_item_put_s { nrf_atfifo_postag_t last_tail; //!< Tail tag value that was here when opening the FIFO to write }nrf_atfifo_item_put_t; /** * @brief FIFO read operation item context. * * Context structure used to mark an opened get operation to properly free an item after reading. */ typedef struct nrf_atfifo_rcontext_s { nrf_atfifo_postag_t last_head; //!< Head tag value that was here when opening the FIFO to read }nrf_atfifo_item_get_t; /** @brief Name of the module used for logger messaging. */ #define NRF_ATFIFO_LOG_NAME atfifo /** * @defgroup nrf_atfifo_instmacros FIFO instance macros * * A group of macros helpful for FIFO instance creation and initialization. * They may be used to create and initialize instances for most use cases. * * FIFO may also be created and initialized directly using * @ref nrf_atfifo_init function. * @{ */ /** * @brief Macro for generating the name for a data buffer. * * The name of the data buffer that would be created by * @ref NRF_ATFIFO_DEF macro. * * @param[in] fifo_id Identifier of the FIFO object. * * @return Name of the buffer variable. * * @note This is auxiliary internal macro and in normal usage * it should not be called. */ #define NRF_ATFIFO_BUF_NAME(fifo_id) CONCAT_2(fifo_id, _data) /** * @brief Macro for generating the name for a FIFO instance. * * The name of the instance variable that will be created by the * @ref NRF_ATFIFO_DEF macro. * * @param[in] fifo_id Identifier of the FIFO object. * * @return Name of the instance variable. * * @note This is auxiliary internal macro and in normal usage * it should not be called. */ #define NRF_ATFIFO_INST_NAME(fifo_id) CONCAT_2(fifo_id, _inst) /** * @brief Macro for creating an instance. * * Creates the FIFO object variable itself. * * Usage example: * @code * NRF_ATFIFO_DEF(my_fifo, uint16_t, 12); * NRF_ATFIFO_INIT(my_fifo); * * uint16_t some_val = 45; * nrf_atfifo_item_put(my_fifo, &some_val, sizeof(some_val), NULL); * nrf_atfifo_item_get(my_fifo, &some_val, sizeof(some_val), NULL); * @endcode * * @param[in] fifo_id Identifier of a FIFO object. * This identifier will be a pointer to the instance. * It makes it possible to use this directly for the functions * that operate on the FIFO. * Because it is a static const object, it should be optimized by the compiler. * @param[in] storage_type Type of data that will be stored in the FIFO. * @param[in] item_cnt Capacity of the created FIFO in maximum number of items that may be stored. * The phisical size of the buffer will be 1 element bigger. */ #define NRF_ATFIFO_DEF(fifo_id, storage_type, item_cnt) \ static storage_type NRF_ATFIFO_BUF_NAME(fifo_id)[(item_cnt)+1]; \ NRF_LOG_INSTANCE_REGISTER(NRF_ATFIFO_LOG_NAME, fifo_id, \ NRF_ATFIFO_CONFIG_INFO_COLOR, \ NRF_ATFIFO_CONFIG_DEBUG_COLOR, \ NRF_ATFIFO_CONFIG_LOG_INIT_FILTER_LEVEL, \ NRF_ATFIFO_CONFIG_LOG_ENABLED ? \ NRF_ATFIFO_CONFIG_LOG_LEVEL : NRF_LOG_SEVERITY_NONE); \ static nrf_atfifo_t NRF_ATFIFO_INST_NAME(fifo_id) = { \ .p_buf = NULL, \ NRF_LOG_INSTANCE_PTR_INIT(p_log, NRF_ATFIFO_LOG_NAME, fifo_id) \ }; \ static nrf_atfifo_t * const fifo_id = &NRF_ATFIFO_INST_NAME(fifo_id) /** * @brief Macro for initializing the FIFO that was previously declared by the macro. * * Use this macro to simplify FIFO initialization. * * @note * This macro can be only used on a FIFO object defined by @ref NRF_ATFIFO_DEF macro. * * @param[in] fifo_id Identifier of the FIFO object. * * @return Value from the @ref nrf_atfifo_init function. */ #define NRF_ATFIFO_INIT(fifo_id) \ nrf_atfifo_init( \ fifo_id, \ NRF_ATFIFO_BUF_NAME(fifo_id), \ sizeof(NRF_ATFIFO_BUF_NAME(fifo_id)), \ sizeof(NRF_ATFIFO_BUF_NAME(fifo_id)[0]) \ ) /** @} */ /** * @brief Function for initializing the FIFO. * * Preparing the FIFO instance to work. * * @param[out] p_fifo FIFO object to initialize. * @param[in,out] p_buf FIFO buffer for storing data. * @param[in] buf_size Total buffer size (has to be divisible by @c item_size). * @param[in] item_size Size of a single item held inside the FIFO. * * @retval NRF_SUCCESS If initialization was successful. * @retval NRF_ERROR_NULL If a NULL pointer is provided as the buffer. * @retval NRF_ERROR_INVALID_LENGTH If size of the buffer provided is not divisible by @c item_size. * * @note * Buffer size must be able to hold one element more than the designed FIFO capacity. * This one, empty element is used for overflow checking. */ ret_code_t nrf_atfifo_init(nrf_atfifo_t * const p_fifo, void * p_buf, uint16_t buf_size, uint16_t item_size); /** * @brief Function for clearing the FIFO. * * Function for clearing the FIFO. * * If this function is called during an opened and uncommitted write operation, * the FIFO is cleared up to the currently ongoing commit. * There is no possibility to cancel an ongoing commit. * * If this function is called during an opened and unflushed read operation, * the read position in the head is set, but copying it into the write head position * is left to read closing operation. * * This way, there is no more data to read, but the memory is released * in the moment when it is safe. * * @param[in,out] p_fifo FIFO object. * * @retval NRF_SUCCESS FIFO totally cleared. * @retval NRF_ERROR_BUSY Function called in the middle of writing or reading operation. * If it is called in the middle of writing operation, * FIFO was cleared up to the already started and uncommitted write. * If it is called in the middle of reading operation, * write head was only moved. It will be copied into read tail when the reading operation * is flushed. */ ret_code_t nrf_atfifo_clear(nrf_atfifo_t * const p_fifo); /** * @brief Function for atomically putting data into the FIFO. * * It uses memcpy function inside and in most situations, it is more suitable to * use @ref nrf_atfifo_item_alloc, write the data, and @ref nrf_atfifo_item_put to store a new value * in a FIFO. * * @param[in,out] p_fifo FIFO object. * @param[in] p_var Variable to copy. * @param[in] size Size of the variable to copy. * Can be smaller or equal to the FIFO item size. * @param[out] p_visible See value returned by @ref nrf_atfifo_item_put. * It may be NULL if the caller does not require the current operation status. * * @retval NRF_SUCCESS If an element has been successfully added to the FIFO. * @retval NRF_ERROR_NO_MEM If the FIFO is full. * * @note * To avoid data copying, you can use the @ref nrf_atfifo_item_alloc and @ref nrf_atfifo_item_put * functions pair. */ ret_code_t nrf_atfifo_alloc_put(nrf_atfifo_t * const p_fifo, void const * const p_var, size_t size, bool * const p_visible); /** * @brief Function for opening the FIFO for writing. * * Function called to start the FIFO write operation and access the given FIFO buffer directly. * * @param[in,out] p_fifo FIFO object. * @param[out] p_context Operation context, required by @ref nrf_atfifo_item_put. * * @return Pointer to the space where variable data can be stored. * NULL if there is no space in the buffer. */ void * nrf_atfifo_item_alloc(nrf_atfifo_t * const p_fifo, nrf_atfifo_item_put_t * p_context); /** * @brief Function for closing the writing operation. * * Puts a previously allocated context into FIFO. * This function must be called to commit an opened write operation. * It sets all the buffers and marks the data, so that it is visible to read. * * @param[in,out] p_fifo FIFO object. * @param[in] p_context Operation context, filled by the @ref nrf_atfifo_item_alloc function. * * @retval true Data is currently ready and will be visible to read. * @retval false The internal commit was marked, but the writing operation interrupted another writing operation. * The data will be available to read when the interrupted operation is committed. */ bool nrf_atfifo_item_put(nrf_atfifo_t * const p_fifo, nrf_atfifo_item_put_t * p_context); /** * @brief Function for getting a single value from the FIFO. * * This function gets the value from the top of the FIFO. * The value is removed from the FIFO memory. * * @param[in,out] p_fifo FIFO object. * @param[out] p_var Pointer to the variable to store the data. * @param[in] size Size of the data to be loaded. * @param[out] p_released See the values returned by @ref nrf_atfifo_item_free. * * @retval NRF_SUCCESS Element was successfully copied from the FIFO memory. * @retval NRF_ERROR_NOT_FOUND No data in the FIFO. */ ret_code_t nrf_atfifo_get_free(nrf_atfifo_t * const p_fifo, void * const p_var, size_t size, bool * p_released); /** * @brief Function for opening the FIFO for reading. * * Function called to start the FIFO read operation and access the given FIFO buffer directly. * * @param[in,out] p_fifo FIFO object. * @param[out] p_context The operation context, required by @ref nrf_atfifo_item_free * * @return Pointer to data buffer or NULL if there is no data in the FIFO. */ void * nrf_atfifo_item_get(nrf_atfifo_t * const p_fifo, nrf_atfifo_item_get_t * p_context); /** * @brief Function for closing the reading operation. * * Function used to finish the reading operation. * If this reading operation does not interrupt another reading operation, the head write buffer is moved. * If this reading operation is placed in the middle of another reading, only the new read pointer is written. * * @param[in,out] p_fifo FIFO object. * @param[in] p_context Context of the reading operation to be closed. * * @retval true This operation is not generated in the middle of another read operation and the write head will be updated to the read head (space is released). * @retval false This operation was performed in the middle of another read operation and the write buffer head was not moved (no space is released). */ bool nrf_atfifo_item_free(nrf_atfifo_t * const p_fifo, nrf_atfifo_item_get_t * p_context); /** @} */ #ifdef __cplusplus } #endif #endif /* NRF_ATFIFO_H__ */