mirror of
https://github.com/jam422470459/EPD-nRF52-hema213.git
synced 2025-12-15 12:58:12 +08:00
move components to SDK dir
This commit is contained in:
159
SDK/12.3.0_d7731ad/components/libraries/atomic_fifo/app_atfifo.c
Normal file
159
SDK/12.3.0_d7731ad/components/libraries/atomic_fifo/app_atfifo.c
Normal file
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* Copyright (c) 2011 - 2017, 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.
|
||||
*
|
||||
*/
|
||||
#include "app_atfifo.h"
|
||||
#include "app_atfifo_internal.h"
|
||||
#include <string.h>
|
||||
#include "app_util.h"
|
||||
|
||||
|
||||
/* Unions testing */
|
||||
STATIC_ASSERT(sizeof(nrf_atfifo_postag_t) == sizeof(uint32_t));
|
||||
|
||||
|
||||
ret_code_t app_atfifo_init(app_atfifo_t * const p_fifo, void * p_buf, uint16_t buf_size, uint16_t item_size)
|
||||
{
|
||||
if(NULL == p_buf)
|
||||
{
|
||||
return NRF_ERROR_NULL;
|
||||
}
|
||||
if(0 != (buf_size % item_size))
|
||||
{
|
||||
return NRF_ERROR_INVALID_LENGTH;
|
||||
}
|
||||
|
||||
p_fifo->p_buf = p_buf;
|
||||
p_fifo->tail.tag = 0;
|
||||
p_fifo->head.tag = 0;
|
||||
p_fifo->buf_size = buf_size;
|
||||
p_fifo->item_size = item_size;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t app_atfifo_clear(app_atfifo_t * const p_fifo)
|
||||
{
|
||||
bool resleased = app_atfifo_space_clear(p_fifo);
|
||||
return resleased ? NRF_SUCCESS : NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t app_atfifo_put(app_atfifo_t * const p_fifo, void const * p_var, size_t size, bool * const p_visible)
|
||||
{
|
||||
app_atfifo_wcontext_t context;
|
||||
bool visible;
|
||||
void * p_d = app_atfifo_wopen(p_fifo, &context, size);
|
||||
if(NULL == p_d)
|
||||
{
|
||||
return NRF_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
memcpy(p_d, p_var, size);
|
||||
|
||||
visible = app_atfifo_wcommit(p_fifo, &context);
|
||||
if(NULL != p_visible)
|
||||
{
|
||||
*p_visible = visible;
|
||||
}
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void * app_atfifo_wopen_internal(app_atfifo_t * const p_fifo, app_atfifo_wcontext_t * p_context)
|
||||
{
|
||||
if(app_atfifo_wspace_req(p_fifo, &(p_context->last_tail)))
|
||||
{
|
||||
return ((uint8_t*)(p_fifo->p_buf)) + p_context->last_tail.pos.wr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool app_atfifo_wcommit(app_atfifo_t * const p_fifo, app_atfifo_wcontext_t * p_context)
|
||||
{
|
||||
if((p_context->last_tail.pos.wr) == (p_context->last_tail.pos.rd))
|
||||
{
|
||||
app_atfifo_wspace_close(p_fifo);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t app_atfifo_get(app_atfifo_t * const p_fifo, void * const p_var, size_t size, bool * p_released)
|
||||
{
|
||||
app_atfifo_rcontext_t context;
|
||||
bool released;
|
||||
void const * p_s = app_atfifo_ropen(p_fifo, &context, size);
|
||||
if(NULL == p_s)
|
||||
{
|
||||
return NRF_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
memcpy(p_var, p_s, size);
|
||||
|
||||
released = app_atfifo_rflush(p_fifo, &context);
|
||||
if(NULL != p_released)
|
||||
{
|
||||
*p_released = released;
|
||||
}
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void const * app_atfifo_ropen_internal(app_atfifo_t * const p_fifo, app_atfifo_rcontext_t * p_context)
|
||||
{
|
||||
if(app_atfifo_rspace_req(p_fifo, &(p_context->last_head)))
|
||||
{
|
||||
return ((uint8_t*)(p_fifo->p_buf)) + p_context->last_head.pos.rd;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool app_atfifo_rflush(app_atfifo_t * const p_fifo, app_atfifo_rcontext_t * p_context)
|
||||
{
|
||||
if((p_context->last_head.pos.wr) == (p_context->last_head.pos.rd))
|
||||
{
|
||||
app_atfifo_rspace_close(p_fifo);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
448
SDK/12.3.0_d7731ad/components/libraries/atomic_fifo/app_atfifo.h
Normal file
448
SDK/12.3.0_d7731ad/components/libraries/atomic_fifo/app_atfifo.h
Normal file
@@ -0,0 +1,448 @@
|
||||
/**
|
||||
* Copyright (c) 2011 - 2017, 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 APP_ATFIFO_H__
|
||||
#define APP_ATFIFO_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "nordic_common.h"
|
||||
#include "nrf_assert.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup app_atfifo Atomic FIFO implementation
|
||||
* @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 FIFO writing:
|
||||
* - Single function for simple access:
|
||||
* @code
|
||||
* if(NRF_SUCCESS != nrf_atfifo_put(&my_fifo, &data, NULL))
|
||||
* {
|
||||
* // Error handling
|
||||
* }
|
||||
* @endcode
|
||||
* - Function pair to limit data coping:
|
||||
* @code
|
||||
* struct point3d
|
||||
* {
|
||||
* int x, y, z;
|
||||
* }point3d_t;
|
||||
* nrf_atfifo_context_t context;
|
||||
* point3d_t * point;
|
||||
*
|
||||
* if(NULL != (point = nrf_atfifo_wopen(&my_fifo, &context)))
|
||||
* {
|
||||
* ret_code_t ret;
|
||||
* point->x = a;
|
||||
* point->y = b;
|
||||
* point->z = c;
|
||||
* if(nrf_atfifo_wcommit(&my_fifo, &context))
|
||||
* {
|
||||
* // Send an information to the rest of the system
|
||||
* // that there is new data in the FIFO available to read.
|
||||
* }
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* // Error handling
|
||||
* }
|
||||
*
|
||||
* @endcode
|
||||
* @note
|
||||
* This Atomic FIFO implementation requires that the operation that was
|
||||
* opened last would be finished (committed/flushed) first.
|
||||
* This is typical for operations performed from the interrupt runtime
|
||||
* when the other operation is performed from 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 read and write position used by fifo head and tail.
|
||||
*/
|
||||
typedef struct nrf_atfifo_postag_pos_s
|
||||
{
|
||||
uint16_t wr; //!< First free space to write a 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 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 app_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 single FIFO item
|
||||
}app_atfifo_t;
|
||||
|
||||
/**
|
||||
* @brief FIFO write operation context
|
||||
*
|
||||
* Context structure used to mark opened commit.
|
||||
* All the data required to properly access the data and then commit it after writing.
|
||||
*/
|
||||
typedef struct app_atfifo_wcontext_s
|
||||
{
|
||||
nrf_atfifo_postag_t last_tail; //!< Tail tag value that was here when opening FIFO to write
|
||||
}app_atfifo_wcontext_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief FIFO read operation context
|
||||
*
|
||||
* Context structure used to mark opened read operation.
|
||||
* All the data required to properly flush the accessed data after accessing.
|
||||
*/
|
||||
typedef struct app_atfifo_rcontext_s
|
||||
{
|
||||
nrf_atfifo_postag_t last_head; //!< Head tag value that was here when opening FIFO to read
|
||||
}app_atfifo_rcontext_t;
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup app_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 app_atfifo_init function.
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Macro to generate the name for data buffer
|
||||
*
|
||||
* The name of the data buffer that would be created by
|
||||
* @ref APP_ATFIFO_DEF macro.
|
||||
*
|
||||
* @param[in] fifo_id The identifier of the FIFO object.
|
||||
*
|
||||
* @return The name of the buffer variable.
|
||||
*/
|
||||
#define APP_ATFIFO_BUF_NAME(fifo_id) CONCAT_2(fifo_id, _data)
|
||||
|
||||
/**
|
||||
* @brief Macro to generate the name for FIFO instance
|
||||
*
|
||||
* The name of instance variable that would be created by
|
||||
* @ref APP_ATFIFO_DEF macro.
|
||||
*
|
||||
* @param[in] fifo_id The identifier of the FIFO object.
|
||||
*
|
||||
* @return The name of the instance variable.
|
||||
*/
|
||||
#define APP_ATFIFO_INST_NAME(fifo_id) CONCAT_2(fifo_id, _inst)
|
||||
|
||||
/**
|
||||
* @brief Instance creation macro
|
||||
*
|
||||
* Creates FIFO object variable itself and
|
||||
*
|
||||
* Use example:
|
||||
* @code
|
||||
* APP_ATFIFO_DEF(my_fifo, uint16_t, 12);
|
||||
* APP_ATFIFO_INIT(my_fifo);
|
||||
*
|
||||
* uint16_t some_val = 45;
|
||||
* app_atfifo_put(my_fifo, &some_val, sizeof(some_val), NULL);
|
||||
* app_atfifo_get(my_fifo, &some_val, sizeof(some_val), NULL);
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] fifo_id The identifier of FIFO object.
|
||||
* This identifier would be a pointer to the instance.
|
||||
* It makes it possible to use this directly for the functions
|
||||
* that operates on the FIFO.
|
||||
* Because it is static const object, it should be optimized by the compiler.
|
||||
* @param[in] storage_type The type of data that would be stored in the FIFO.
|
||||
* @param[in] item_cnt The capacity of created FIFO in maximum number of items that may be stored.
|
||||
* The phisical size of the buffer would be 1 element bigger.
|
||||
*/
|
||||
#define APP_ATFIFO_DEF(fifo_id, storage_type, item_cnt) \
|
||||
static storage_type APP_ATFIFO_BUF_NAME(fifo_id)[(item_cnt)+1]; \
|
||||
static app_atfifo_t APP_ATFIFO_INST_NAME(fifo_id); \
|
||||
static app_atfifo_t * const fifo_id = &APP_ATFIFO_INST_NAME(fifo_id)
|
||||
|
||||
/**
|
||||
* @brief Use this macro to initialize FIFO declared previously by the macro
|
||||
*
|
||||
* Use this macro to simplify FIFO initialization.
|
||||
*
|
||||
* @note
|
||||
* This macro can be only used on FIFO object defined by @ref APP_ATFIFO_DEF macro.
|
||||
*
|
||||
* @param[in] fifo_id The identifier of the FIFO object.
|
||||
*
|
||||
* @return The value from @ref app_atfifo_init function.
|
||||
*/
|
||||
#define APP_ATFIFO_INIT(fifo_id) \
|
||||
app_atfifo_init( \
|
||||
fifo_id, \
|
||||
&APP_ATFIFO_BUF_NAME(fifo_id), \
|
||||
sizeof(APP_ATFIFO_BUF_NAME(fifo_id)), \
|
||||
sizeof(APP_ATFIFO_BUF_NAME(fifo_id)[0]) \
|
||||
)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Initializing the FIFO
|
||||
*
|
||||
* Preparing 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 single item hold inside the FIFO.
|
||||
*
|
||||
* @retval NRF_SUCCESS If initialization was successful.
|
||||
* @retval NRF_ERROR_NULL If a NULL pointer is provided as buffer.
|
||||
* @retval NRF_ERROR_INVALID_LENGTH If size of buffer provided is divisible by @c item_size.
|
||||
*
|
||||
* @note
|
||||
* Buffer size has to be able to fit 1 element more than designed FIFO capacity.
|
||||
* This one, empty element is used for overflow checking.
|
||||
*/
|
||||
ret_code_t app_atfifo_init(app_atfifo_t * const p_fifo, void * p_buf, uint16_t buf_size, uint16_t item_size);
|
||||
|
||||
/**
|
||||
* @brief Clear the FIFO
|
||||
*
|
||||
* Clearing the FIFO.
|
||||
*
|
||||
* If this function is called during some opened and uncommitted write operation,
|
||||
* the FIFO would be cleared up to the currently ongoing commit.
|
||||
* There is no possibility to cancel ongoing commit.
|
||||
*
|
||||
* If this function is called during some opened and unflushed read operation,
|
||||
* the read position in head would be set, but copying it into write head position
|
||||
* would be left to read closing operation.
|
||||
*
|
||||
* This way there would be no more data to read, but the memory would be 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 we are in the middle of writing operation,
|
||||
* FIFO was cleared up to the already started, and uncommitted write.
|
||||
* If we are in the middle of write operation,
|
||||
* write head was only moved. It would be copied into read tail when reading operation
|
||||
* would be flushed.
|
||||
*/
|
||||
ret_code_t app_atfifo_clear(app_atfifo_t * const p_fifo);
|
||||
|
||||
/**
|
||||
* @brief Put data into FIFO
|
||||
*
|
||||
* Function to that puts data into the FIFO atomically.
|
||||
*
|
||||
* @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 app_atfifo_wcommit.
|
||||
* If may be NULL if the caller does not care about 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 one may use @ref app_atfifo_wopen and @ref app_atfifo_wcommit
|
||||
* functions pair.
|
||||
*/
|
||||
ret_code_t app_atfifo_put(app_atfifo_t * const p_fifo, void const * const p_var, size_t size, bool * const p_visible);
|
||||
|
||||
/**
|
||||
* @brief Open FIFO for writing, internal function
|
||||
*
|
||||
* Function called to start FIFO write 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 app_atfifo_wcommit.
|
||||
*
|
||||
* @return Pointer to the space where variable data may be stored.
|
||||
* NULL if there is no space in the buffer.
|
||||
*
|
||||
* @note
|
||||
* Do not use this function directly.
|
||||
* Use @ref app_atfifo_wopen instead.
|
||||
*/
|
||||
void * app_atfifo_wopen_internal(app_atfifo_t * const p_fifo, app_atfifo_wcontext_t * p_context);
|
||||
|
||||
/**
|
||||
* @brief Open FIFO for writing
|
||||
*
|
||||
* Function called to start FIFO write 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 app_atfifo_wcommit.
|
||||
* @param[in] size Requested size of the buffer. Currently used only for integrity checking when debugging.
|
||||
*
|
||||
* @return Pointer to the space where variable data may be stored.
|
||||
* NULL if there is no space in the buffer.
|
||||
*
|
||||
* @note Always finish writing operation by @ref app_atfifo_wcommit
|
||||
*/
|
||||
static inline void * app_atfifo_wopen(app_atfifo_t * const p_fifo, app_atfifo_wcontext_t * p_context, size_t size)
|
||||
{
|
||||
ASSERT(size <= p_fifo->item_size);
|
||||
UNUSED_PARAMETER(size);
|
||||
return app_atfifo_wopen_internal(p_fifo, p_context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Close the writing operation
|
||||
*
|
||||
* Function need to be called to finally commit opened write operation.
|
||||
* It sets all the buffers and finally mark the data to be visible to read.
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
* @param[in] p_context Operation context, filled by the @ref app_atfifo_wopen function.
|
||||
*
|
||||
* @retval true The data is actually ready and would be visible to read.
|
||||
* @retval false The internal commit was marked, but the writing operation interrupted another writing operation.
|
||||
* The data would be available to read when the interrupted operation would be committed.
|
||||
*/
|
||||
bool app_atfifo_wcommit(app_atfifo_t * const p_fifo, app_atfifo_wcontext_t * p_context);
|
||||
|
||||
/**
|
||||
* @brief Get single value from the FIFO
|
||||
*
|
||||
* Function gets the value from the top from 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 data.
|
||||
* @param[in] size Size of the data we are going to load.
|
||||
* @param[out] p_released See the values returned by @ref app_atfifo_rflush.
|
||||
*
|
||||
* @retval NRF_SUCCESS Element was successfully copied from FIFO memory.
|
||||
* @retval NRF_ERROR_NOT_FOUND No data in the FIFO.
|
||||
*/
|
||||
ret_code_t app_atfifo_get(app_atfifo_t * const p_fifo, void * const p_var, size_t size, bool * p_released);
|
||||
|
||||
/**
|
||||
* @brief Open FIFO for reading, internal function
|
||||
*
|
||||
* Function called to start 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 app_atfifo_rflush
|
||||
*
|
||||
* @return Pointer to data buffer or NULL if there is no data in the FIFO.
|
||||
*
|
||||
* @note
|
||||
* Do not use this function directly.
|
||||
* Use @ref app_atfifo_ropen instead.
|
||||
*/
|
||||
void const * app_atfifo_ropen_internal(app_atfifo_t * const p_fifo, app_atfifo_rcontext_t * p_context);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Open FIFO for reading
|
||||
*
|
||||
* Function called to start FIFO read operation and access the FIFO buffer directly.
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
* @param[out] p_context The operation context, required by @ref app_atfifo_rflush
|
||||
* @param[in] size Requested size of the buffer. Currently used only for integrity checking when debugging.
|
||||
*
|
||||
* @return Pointer to data buffer or NULL if there is no data in the FIFO.
|
||||
*/
|
||||
static inline void const * app_atfifo_ropen(app_atfifo_t * const p_fifo, app_atfifo_rcontext_t * p_context, size_t size)
|
||||
{
|
||||
ASSERT(size <= p_fifo->item_size);
|
||||
UNUSED_PARAMETER(size);
|
||||
return app_atfifo_ropen_internal(p_fifo, p_context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Close reading operation
|
||||
*
|
||||
* Function used to finish reading operation.
|
||||
* If this reading operation did not interrupt another reading operation the head write buffer is moved.
|
||||
* If this reading operation was placed in the middle of another reading, the new read pointer is only written.
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
* @param[in] p_context Context of the reading operation that we are going to close.
|
||||
*
|
||||
* @retval true This operation is not generated in the middle of another read operation and the write head would be updated to 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 app_atfifo_rflush(app_atfifo_t * const p_fifo, app_atfifo_rcontext_t * p_context);
|
||||
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* APP_ATFIFO_H__ */
|
||||
@@ -0,0 +1,576 @@
|
||||
/**
|
||||
* Copyright (c) 2011 - 2017, 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.
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Atomic FIFO internal file
|
||||
*
|
||||
* This file should be included only by app_atfifo internally.
|
||||
* Needs app_atfifo.h included first.
|
||||
*/
|
||||
#ifndef APP_ATFIFO_H__
|
||||
#error This is internal file. Do not include this file in your program.
|
||||
#endif
|
||||
|
||||
#ifndef APP_ATFIFO_INTERNAL_H__
|
||||
#define APP_ATFIFO_INTERNAL_H__
|
||||
#include <stddef.h>
|
||||
#include "nrf.h"
|
||||
#include "app_util.h"
|
||||
#include "nordic_common.h"
|
||||
|
||||
#if ((__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U)) == 0
|
||||
#error Unsupported core version
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Make sure that rd and wr pos in a tag are aligned like expected
|
||||
* Changing this would require changes inside assembly code!
|
||||
*/
|
||||
STATIC_ASSERT(offsetof(nrf_atfifo_postag_pos_t, wr) == 0);
|
||||
STATIC_ASSERT(offsetof(nrf_atfifo_postag_pos_t, rd) == 2);
|
||||
|
||||
/**
|
||||
* @brief Atomically reserve space for new write
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
* @param[out] old_tail Tail position tag before new space was reserved
|
||||
*
|
||||
* @retval true Space available
|
||||
* @retval false Memory full
|
||||
*
|
||||
* @sa app_atfifo_wspace_close
|
||||
*/
|
||||
static bool app_atfifo_wspace_req(app_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_tail);
|
||||
|
||||
/**
|
||||
* @brief Atomically mark all written data available
|
||||
*
|
||||
* This function marks all data available for reading.
|
||||
* This marking is done by copying tail.pos.wr into tail.pos.rd.
|
||||
*
|
||||
* It has to be called only when closing the first write.
|
||||
* It cannot be called if some write access was interrupted.
|
||||
* See the code below:
|
||||
* @code
|
||||
* if(old_tail.pos.wr == old_tail.pos.rd)
|
||||
* {
|
||||
* app_atfifo_wspace_close(my_fifo);
|
||||
* return true;
|
||||
* }
|
||||
* return false;
|
||||
* @endcode
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
*
|
||||
* @sa app_atfifo_wspace_req
|
||||
*/
|
||||
static void app_atfifo_wspace_close(app_atfifo_t * const p_fifo);
|
||||
|
||||
/**
|
||||
* @brief Atomically get part of the buffer to read data
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
* @param[out] old_head Head position tag before data buffer was read
|
||||
*
|
||||
* @retval true Data available for reading
|
||||
* @retval false No data in the buffer
|
||||
*
|
||||
* @sa app_atfifo_rspace_close
|
||||
*/
|
||||
static bool app_atfifo_rspace_req(app_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_head);
|
||||
|
||||
/**
|
||||
* @brief Atomically release all read data
|
||||
*
|
||||
* This function marks all data that was actually read as free space,
|
||||
* available for writing.
|
||||
* This marking is done by copying head.pos.rd into head.pos.wr.
|
||||
*
|
||||
* It has to be called only when closing the first read.
|
||||
* It cannot be called when current read access interrupted some other read access.
|
||||
* See code below:
|
||||
* @code
|
||||
* if(old_head.pos.wr == old_head.pos.rd)
|
||||
* {
|
||||
* app_atfifo_rspace_close(my_fifo);
|
||||
* return true;
|
||||
* }
|
||||
* return false;
|
||||
* @endcode
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
*
|
||||
* @sa app_atfifo_rspace_req
|
||||
*/
|
||||
static void app_atfifo_rspace_close(app_atfifo_t * const p_fifo);
|
||||
|
||||
/**
|
||||
* @brief Safely clear the FIFO, internal function
|
||||
*
|
||||
* This function realizes the functionality required by @ref app_atfifo_clear.
|
||||
*
|
||||
* @param[in,out] p_fifo FIFO object.
|
||||
*
|
||||
* @retval true All the data was released
|
||||
* @retval false All the data available for releasing was released, but there is some pending transfer.
|
||||
*/
|
||||
static bool app_atfifo_space_clear(app_atfifo_t * const p_fifo);
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Implementation starts here
|
||||
*/
|
||||
|
||||
#if defined ( __CC_ARM )
|
||||
|
||||
|
||||
__ASM bool app_atfifo_wspace_req(app_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_tail)
|
||||
{
|
||||
/* Registry usage:
|
||||
* R0 - p_fifo
|
||||
* R1 - p_old_tail
|
||||
* R2 - internal variable old_tail (saved by caller)
|
||||
* R3 - internal variable new_tail (saved by caller)
|
||||
* R4 - internal temporary register (saved by this function)
|
||||
* R5 - not used stored to keep the stack aligned to 8 bytes
|
||||
* Returned value:
|
||||
* R0 (bool - 32 bits)
|
||||
*/
|
||||
push {r4, r5}
|
||||
app_atfifo_wspace_req_repeat
|
||||
/* Load tail tag and set memory monitor !!! R2 - old tail !!! */
|
||||
ldrex r2, [r0, #__cpp(offsetof(app_atfifo_t, tail))]
|
||||
/* Extract write position !!! R3 !!! */
|
||||
uxth r3, r2
|
||||
/* Increment address with overload support !!! R4 used temporary !!! */
|
||||
ldrh r4, [r0, #__cpp(offsetof(app_atfifo_t, item_size))]
|
||||
add r3, r4
|
||||
ldrh r4, [r0, #__cpp(offsetof(app_atfifo_t, buf_size))]
|
||||
cmp r3, r4
|
||||
it hs
|
||||
subhs r3, r3, r4
|
||||
|
||||
/* Check if FIFO would overload after making this increment !!! R4 used temporary !!! */
|
||||
ldrh r4, [r0, #__cpp(offsetof(app_atfifo_t, head) + offsetof(nrf_atfifo_postag_pos_t, wr))]
|
||||
cmp r3, r4
|
||||
ittt eq
|
||||
clrexeq
|
||||
moveq r0, #__cpp(false)
|
||||
beq app_atfifo_wspace_req_exit
|
||||
|
||||
/* Pack everything back !!! R3 - new tail !!! */
|
||||
/* Copy lower byte from new_tail, and higher byte is a value from the top of old_tail */
|
||||
pkhbt r3, r3, r2
|
||||
|
||||
/* Store new value clearing memory monitor !!! R4 used temporary !!! */
|
||||
strex r4, r3, [r0, #__cpp(offsetof(app_atfifo_t, tail))]
|
||||
cmp r4, #0
|
||||
bne app_atfifo_wspace_req_repeat
|
||||
|
||||
/* Return true */
|
||||
mov r0, #__cpp(true)
|
||||
app_atfifo_wspace_req_exit
|
||||
/* Save old tail */
|
||||
str r2, [r1]
|
||||
pop {r4, r5}
|
||||
bx lr
|
||||
}
|
||||
|
||||
|
||||
__ASM void app_atfifo_wspace_close(app_atfifo_t * const p_fifo)
|
||||
{
|
||||
/* Registry usage:
|
||||
* R0 - p_fifo
|
||||
* R1 - internal temporary register
|
||||
* R2 - new_tail
|
||||
*/
|
||||
app_atfifo_wspace_close_repeat
|
||||
ldrex r2, [r0, #__cpp(offsetof(app_atfifo_t, tail))]
|
||||
/* Copy from lower byte to higher */
|
||||
pkhbt r2, r2, r2, lsl #16
|
||||
|
||||
strex r1, r2, [r0, #__cpp(offsetof(app_atfifo_t, tail))]
|
||||
cmp r1, #0
|
||||
bne app_atfifo_wspace_close_repeat
|
||||
bx lr
|
||||
}
|
||||
|
||||
|
||||
__ASM bool app_atfifo_rspace_req(app_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_head)
|
||||
{
|
||||
/* Registry usage:
|
||||
* R0 - p_fifo
|
||||
* R1 - p_old_head
|
||||
* R2 - internal variable old_head (saved by caller)
|
||||
* R3 - internal variable new_head (saved by caller)
|
||||
* R4 - internal temporary register (saved by this function)
|
||||
* R5 - not used stored to keep the stack aligned to 8 bytes
|
||||
* Returned value:
|
||||
* R0 (bool - 32 bits)
|
||||
*/
|
||||
push {r4, r5}
|
||||
app_atfifo_rspace_req_repeat
|
||||
/* Load tail tag and set memory monitor !!! R2 - old tail !!! */
|
||||
ldrex r2, [r0, #__cpp(offsetof(app_atfifo_t, head))]
|
||||
/* Extract read position !!! R3 !!! */
|
||||
uxth r3, r2, ror #16
|
||||
|
||||
/* Check if we have any data !!! R4 used temporary !!! */
|
||||
ldrh r4, [r0, #__cpp(offsetof(app_atfifo_t, tail) + offsetof(nrf_atfifo_postag_pos_t, rd))]
|
||||
cmp r3, r4
|
||||
ittt eq
|
||||
clrexeq
|
||||
moveq r0, #__cpp(false)
|
||||
beq app_atfifo_rspace_req_exit
|
||||
|
||||
/* Increment address with overload support !!! R4 used temporary !!! */
|
||||
ldrh r4, [r0, #__cpp(offsetof(app_atfifo_t, item_size))]
|
||||
add r3, r4
|
||||
ldrh r4, [r0, #__cpp(offsetof(app_atfifo_t, buf_size))]
|
||||
cmp r3, r4
|
||||
it hs
|
||||
subhs r3, r3, r4
|
||||
|
||||
/* Pack everything back !!! R3 - new tail !!! */
|
||||
/* Copy lower byte from old_head, and higher byte is a value from write_pos */
|
||||
pkhbt r3, r2, r3, lsl #16
|
||||
|
||||
/* Store new value clearing memory monitor !!! R4 used temporary !!! */
|
||||
strex r4, r3, [r0, #__cpp(offsetof(app_atfifo_t, head))]
|
||||
cmp r4, #0
|
||||
bne app_atfifo_rspace_req_repeat
|
||||
|
||||
/* Return true */
|
||||
mov r0, #__cpp(true)
|
||||
app_atfifo_rspace_req_exit
|
||||
/* Save old head */
|
||||
str r2, [r1]
|
||||
pop {r4, r5}
|
||||
bx lr
|
||||
}
|
||||
|
||||
|
||||
__ASM void app_atfifo_rspace_close(app_atfifo_t * const p_fifo)
|
||||
{
|
||||
/* Registry usage:
|
||||
* R0 - p_fifo
|
||||
* R1 - internal temporary register
|
||||
* R2 - new_tail
|
||||
*/
|
||||
app_atfifo_rspace_close_repeat
|
||||
ldrex r2, [r0, #__cpp(offsetof(app_atfifo_t, head))]
|
||||
/* Copy from higher byte to lower */
|
||||
pkhtb r2, r2, r2, asr #16
|
||||
|
||||
strex r1, r2, [r0, #__cpp(offsetof(app_atfifo_t, head))]
|
||||
cmp r1, #0
|
||||
bne app_atfifo_rspace_close_repeat
|
||||
bx lr
|
||||
}
|
||||
|
||||
|
||||
__ASM bool app_atfifo_space_clear(app_atfifo_t * const p_fifo)
|
||||
{
|
||||
/* Registry usage:
|
||||
* R0 - p_fifo as input, bool output after
|
||||
* R1 - tail, rd pointer, new_head
|
||||
* R2 - head_old, destroyed when creating new_head
|
||||
* R3 - p_fifo - copy
|
||||
*/
|
||||
mov r3, r0
|
||||
app_atfifo_space_clear_repeat
|
||||
/* Load old head in !!! R2 register !!! and read pointer of tail in !!! R1 register !!! */
|
||||
ldrex r2, [r3, #__cpp(offsetof(app_atfifo_t, head))]
|
||||
ldrh r1, [r3, #__cpp(offsetof(app_atfifo_t, tail) + offsetof(nrf_atfifo_postag_pos_t, rd))]
|
||||
cmp r2, r2, ror #16
|
||||
/* Return false as default */
|
||||
mov r0, #__cpp(false)
|
||||
/* Create new head in !!! R1 register !!! Data in !!! R2 register broken !!! */
|
||||
itett ne
|
||||
uxthne r2, r2
|
||||
orreq r1, r1, r1, lsl #16
|
||||
orrne r1, r2, r1, lsl #16
|
||||
|
||||
/* Skip header test */
|
||||
bne app_atfifo_space_clear_head_test_skip
|
||||
|
||||
/* Load whole tail and test it !!! R2 used !!! */
|
||||
ldr r2, [r3, #__cpp(offsetof(app_atfifo_t, tail))]
|
||||
cmp r2, r2, ror #16
|
||||
/* Return true if equal */
|
||||
it eq
|
||||
moveq r0, #__cpp(true)
|
||||
|
||||
app_atfifo_space_clear_head_test_skip
|
||||
/* Store and test if success !!! R2 used temporary !!! */
|
||||
strex r2, r1, [r3, #__cpp(offsetof(app_atfifo_t, head))]
|
||||
cmp r2, #0
|
||||
bne app_atfifo_space_clear_repeat
|
||||
bx lr
|
||||
}
|
||||
|
||||
#elif defined ( __ICCARM__ ) || defined ( __GNUC__ )
|
||||
|
||||
bool app_atfifo_wspace_req(app_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_tail)
|
||||
{
|
||||
volatile bool ret;
|
||||
volatile uint32_t old_tail;
|
||||
uint32_t new_tail;
|
||||
uint32_t temp;
|
||||
|
||||
__ASM volatile(
|
||||
/* For more comments see Keil version above */
|
||||
"1: \n"
|
||||
" ldrex %[old_tail], [%[p_fifo], %[offset_tail]] \n"
|
||||
" uxth %[new_tail], %[old_tail] \n"
|
||||
" \n"
|
||||
" ldrh %[temp], [%[p_fifo], %[offset_item_size]] \n"
|
||||
" add %[new_tail], %[temp] \n"
|
||||
" ldrh %[temp], [%[p_fifo], %[offset_buf_size]] \n"
|
||||
" cmp %[new_tail], %[temp] \n"
|
||||
" it hs \n"
|
||||
" subhs %[new_tail], %[new_tail], %[temp] \n"
|
||||
" \n"
|
||||
" ldrh %[temp], [%[p_fifo], %[offset_head_wr]] \n"
|
||||
" cmp %[new_tail], %[temp] \n"
|
||||
" ittt eq \n"
|
||||
" clrexeq \n"
|
||||
" moveq %[ret], %[false_val] \n"
|
||||
" beq.n 2f \n"
|
||||
" \n"
|
||||
" pkhbt %[new_tail], %[new_tail], %[old_tail] \n"
|
||||
" \n"
|
||||
" strex %[temp], %[new_tail], [%[p_fifo], %[offset_tail]] \n"
|
||||
" cmp %[temp], #0 \n"
|
||||
" bne.n 1b \n"
|
||||
" \n"
|
||||
" mov %[ret], %[true_val] \n"
|
||||
"2: \n"
|
||||
: /* Output operands */
|
||||
[ret] "=r"(ret),
|
||||
[temp] "=&r"(temp),
|
||||
[old_tail]"=&r"(old_tail),
|
||||
[new_tail]"=&r"(new_tail)
|
||||
: /* Input operands */
|
||||
[p_fifo] "r"(p_fifo),
|
||||
[offset_tail] "J"(offsetof(app_atfifo_t, tail)),
|
||||
[offset_head_wr] "J"(offsetof(app_atfifo_t, head) + offsetof(nrf_atfifo_postag_pos_t, wr)),
|
||||
[offset_item_size]"J"(offsetof(app_atfifo_t, item_size)),
|
||||
[offset_buf_size] "J"(offsetof(app_atfifo_t, buf_size)),
|
||||
[true_val] "I"(true),
|
||||
[false_val] "I"(false)
|
||||
: /* Clobbers */
|
||||
"cc");
|
||||
|
||||
p_old_tail->tag = old_tail;
|
||||
UNUSED_VARIABLE(new_tail);
|
||||
UNUSED_VARIABLE(temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void app_atfifo_wspace_close(app_atfifo_t * const p_fifo)
|
||||
{
|
||||
uint32_t temp;
|
||||
uint32_t new_tail;
|
||||
|
||||
__ASM volatile(
|
||||
/* For more comments see Keil version above */
|
||||
"1: \n"
|
||||
" ldrex %[new_tail], [%[p_fifo], %[offset_tail]] \n"
|
||||
" pkhbt %[new_tail],%[new_tail], %[new_tail], lsl #16 \n"
|
||||
" \n"
|
||||
" strex %[temp], %[new_tail], [%[p_fifo], %[offset_tail]] \n"
|
||||
" cmp %[temp], #0 \n"
|
||||
" bne.n 1b \n"
|
||||
: /* Output operands */
|
||||
[temp] "=&r"(temp),
|
||||
[new_tail] "=&r"(new_tail)
|
||||
: /* Input operands */
|
||||
[p_fifo] "r"(p_fifo),
|
||||
[offset_tail] "J"(offsetof(app_atfifo_t, tail))
|
||||
: /* Clobbers */
|
||||
"cc");
|
||||
|
||||
UNUSED_VARIABLE(temp);
|
||||
UNUSED_VARIABLE(new_tail);
|
||||
}
|
||||
|
||||
|
||||
bool app_atfifo_rspace_req(app_atfifo_t * const p_fifo, nrf_atfifo_postag_t * const p_old_head)
|
||||
{
|
||||
volatile bool ret;
|
||||
volatile uint32_t old_head;
|
||||
uint32_t new_head;
|
||||
uint32_t temp;
|
||||
|
||||
__ASM volatile(
|
||||
/* For more comments see Keil version above */
|
||||
"1: \n"
|
||||
" ldrex %[old_head], [%[p_fifo], %[offset_head]] \n"
|
||||
" uxth %[new_head], %[old_head], ror #16 \n"
|
||||
" \n"
|
||||
" ldrh %[temp], [%[p_fifo], %[offset_tail_rd]] \n"
|
||||
" cmp %[new_head], %[temp] \n"
|
||||
" ittt eq \n"
|
||||
" clrexeq \n"
|
||||
" moveq %[ret], %[false_val] \n"
|
||||
" beq.n 2f \n"
|
||||
" \n"
|
||||
" ldrh %[temp], [%[p_fifo], %[offset_item_size]] \n"
|
||||
" add %[new_head], %[temp] \n"
|
||||
" ldrh %[temp], [%[p_fifo], %[offset_buf_size]] \n"
|
||||
" cmp %[new_head], %[temp] \n"
|
||||
" it hs \n"
|
||||
" subhs %[new_head], %[new_head], %[temp] \n"
|
||||
" \n"
|
||||
" pkhbt %[new_head], %[old_head], %[new_head], lsl #16 \n"
|
||||
" \n"
|
||||
" strex %[temp], %[new_head], [%[p_fifo], %[offset_head]] \n"
|
||||
" cmp %[temp], #0 \n"
|
||||
" bne.n 1b \n"
|
||||
" \n"
|
||||
" mov %[ret], %[true_val] \n"
|
||||
"2: \n"
|
||||
: /* Output operands */
|
||||
[ret] "=r"(ret),
|
||||
[temp] "=&r"(temp),
|
||||
[old_head]"=&r"(old_head),
|
||||
[new_head]"=&r"(new_head)
|
||||
: /* Input operands */
|
||||
[p_fifo] "r"(p_fifo),
|
||||
[offset_head] "J"(offsetof(app_atfifo_t, head)),
|
||||
[offset_tail_rd] "J"(offsetof(app_atfifo_t, tail) + offsetof(nrf_atfifo_postag_pos_t, rd)),
|
||||
[offset_item_size]"J"(offsetof(app_atfifo_t, item_size)),
|
||||
[offset_buf_size] "J"(offsetof(app_atfifo_t, buf_size)),
|
||||
[true_val] "I"(true),
|
||||
[false_val] "I"(false)
|
||||
: /* Clobbers */
|
||||
"cc");
|
||||
|
||||
p_old_head->tag = old_head;
|
||||
UNUSED_VARIABLE(new_head);
|
||||
UNUSED_VARIABLE(temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void app_atfifo_rspace_close(app_atfifo_t * const p_fifo)
|
||||
{
|
||||
uint32_t temp;
|
||||
uint32_t new_head;
|
||||
|
||||
__ASM volatile(
|
||||
/* For more comments see Keil version above */
|
||||
"1: \n"
|
||||
" ldrex %[new_head], [%[p_fifo], %[offset_head]] \n"
|
||||
" pkhtb %[new_head],%[new_head], %[new_head], asr #16 \n"
|
||||
" \n"
|
||||
" strex %[temp], %[new_head], [%[p_fifo], %[offset_head]] \n"
|
||||
" cmp %[temp], #0 \n"
|
||||
" bne.n 1b \n"
|
||||
: /* Output operands */
|
||||
[temp] "=&r"(temp),
|
||||
[new_head] "=&r"(new_head)
|
||||
: /* Input operands */
|
||||
[p_fifo] "r"(p_fifo),
|
||||
[offset_head] "J"(offsetof(app_atfifo_t, head))
|
||||
: /* Clobbers */
|
||||
"cc");
|
||||
|
||||
UNUSED_VARIABLE(temp);
|
||||
UNUSED_VARIABLE(new_head);
|
||||
}
|
||||
|
||||
|
||||
bool app_atfifo_space_clear(app_atfifo_t * const p_fifo)
|
||||
{
|
||||
volatile bool ret;
|
||||
uint32_t old_head; /* This variable is left broken after assembly code finishes */
|
||||
uint32_t new_head;
|
||||
|
||||
__ASM volatile(
|
||||
"1: \n"
|
||||
" ldrex %[old_head], [%[p_fifo], %[offset_head]] \n"
|
||||
" ldrh %[new_head], [%[p_fifo], %[offset_tail_rd]] \n"
|
||||
" cmp %[old_head], %[old_head], ror #16 \n"
|
||||
" \n"
|
||||
" mov %[ret], %[false_val] \n"
|
||||
" \n"
|
||||
" itett ne \n"
|
||||
" uxthne %[old_head], %[old_head] \n"
|
||||
" orreq %[new_head], %[new_head], %[new_head], lsl #16 \n"
|
||||
" orrne %[new_head], %[old_head], %[new_head], lsl #16 \n"
|
||||
" \n"
|
||||
" bne.n 2f \n"
|
||||
" \n"
|
||||
" ldr %[old_head], [%[p_fifo], %[offset_tail]] \n"
|
||||
" cmp %[old_head], %[old_head], ror #16 \n"
|
||||
" it eq \n"
|
||||
" moveq %[ret], %[true_val] \n"
|
||||
" \n"
|
||||
"2: \n"
|
||||
" strex %[old_head], %[new_head], [%[p_fifo], %[offset_head]] \n"
|
||||
" cmp %[old_head], #0 \n"
|
||||
" bne.n 1b \n"
|
||||
: /* Output operands */
|
||||
[ret] "=&r"(ret),
|
||||
[old_head] "=&r"(old_head),
|
||||
[new_head] "=&r"(new_head)
|
||||
: /* Input operands */
|
||||
[p_fifo] "r"(p_fifo),
|
||||
[offset_head] "J"(offsetof(app_atfifo_t, head)),
|
||||
[offset_tail] "J"(offsetof(app_atfifo_t, tail)),
|
||||
[offset_tail_rd] "J"(offsetof(app_atfifo_t, tail) + offsetof(nrf_atfifo_postag_pos_t, rd)),
|
||||
[true_val] "I"(true),
|
||||
[false_val] "I"(false)
|
||||
: /* Clobbers */
|
||||
"cc");
|
||||
|
||||
UNUSED_VARIABLE(old_head);
|
||||
UNUSED_VARIABLE(new_head);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
#error Unsupported compiler
|
||||
#endif
|
||||
|
||||
#endif /* APP_ATFIFO_INTERNAL_H__ */
|
||||
Reference in New Issue
Block a user