549 lines
19 KiB
C
549 lines
19 KiB
C
/*
|
|
* Copyright (c) 2012-2022 DSR Corporation, Denver CO, USA
|
|
* Copyright (c) 2021-2022 Espressif Systems (Shanghai) PTE LTD
|
|
* 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 Espressif Systems
|
|
* 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 the copyright holder nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* 4. Any software provided in binary form under this license must not be reverse
|
|
* engineered, decompiled, modified and/or disassembled.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
|
|
*/
|
|
/* PURPOSE: Declare ring buffer internals
|
|
*/
|
|
|
|
#ifndef ZB_RINGBUFFER_H
|
|
#define ZB_RINGBUFFER_H 1
|
|
|
|
/*! @cond internals_doc */
|
|
/**
|
|
@addtogroup ZB_BASE
|
|
@{
|
|
*/
|
|
|
|
|
|
/**
|
|
\par Generic ring buffer macros
|
|
*/
|
|
|
|
/**
|
|
Declare ring buffer for entries of given type and capacity.
|
|
This is typedef, not variable declaration.
|
|
|
|
@param type_name_prefix - prefix for names (like xxx_s, xxx_t)
|
|
@param ent_type - type of the ring buffer entry
|
|
@param capacity - ring buffer capacity
|
|
*/
|
|
#define ZB_RING_BUFFER_DECLARE(type_name_prefix, ent_type, capacity) \
|
|
typedef struct type_name_prefix ## _s \
|
|
{ \
|
|
zb_ushort_t read_i; \
|
|
zb_ushort_t write_i; \
|
|
zb_ushort_t written; \
|
|
ent_type ring_buf[capacity]; \
|
|
} type_name_prefix ## _t
|
|
|
|
|
|
/**
|
|
* Initialize ring buffer internals
|
|
*/
|
|
#define ZB_RING_BUFFER_INIT(rb) ( (rb)->read_i = (rb)->write_i = (rb)->written = 0U)
|
|
|
|
/**
|
|
* Return ring buffer capacity
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
*/
|
|
#define ZB_RING_BUFFER_CAPACITY(rb) ((sizeof((rb)->ring_buf) / sizeof((rb)->ring_buf[0])))
|
|
|
|
/**
|
|
* Return 1 if ring buffer is full
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
*/
|
|
#define ZB_RING_BUFFER_IS_FULL(rb) ((zb_uint_t)(rb)->written >= ZB_RING_BUFFER_CAPACITY(rb))
|
|
|
|
/**
|
|
* Return 1 if ring buffer is empty
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
*/
|
|
#define ZB_RING_BUFFER_IS_EMPTY(rb) ((rb)->written == 0U)
|
|
|
|
|
|
/**
|
|
* Return free space available in the ring buffer
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
*/
|
|
#define ZB_RING_BUFFER_FREE_SPACE(rb) (ZB_RING_BUFFER_CAPACITY(rb) - (zb_uint_t)(rb)->written)
|
|
|
|
/**
|
|
* Reserve slot in the ring buffer but do not update pointers
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
* @return Pointer to the ring buffer entry or NULL if ring buffer is full
|
|
*/
|
|
#define ZB_RING_BUFFER_PUT_RESERVE(rb) \
|
|
( \
|
|
ZB_RING_BUFFER_IS_FULL(rb) ? NULL \
|
|
: (rb)->ring_buf + (rb)->write_i \
|
|
)
|
|
|
|
#define ZB_RING_BUFFER_PUT_HEAD_RESERVE_IDX(rb) \
|
|
( \
|
|
((rb)->read_i > 0U) ? \
|
|
((rb)->read_i - 1U) : (ZB_RING_BUFFER_CAPACITY(rb) - 1U) \
|
|
)
|
|
|
|
#define ZB_RING_BUFFER_PUT_HEAD_RESERVE(rb) \
|
|
( \
|
|
ZB_RING_BUFFER_IS_FULL(rb) ? NULL \
|
|
: ((rb)->ring_buf + ZB_RING_BUFFER_PUT_HEAD_RESERVE_IDX(rb)) \
|
|
)
|
|
|
|
/**
|
|
* Put to the ring buffer.
|
|
* Get free slot from the ring buffer, return pointer to it.
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
* @return nothing
|
|
*/
|
|
#define ZB_RING_BUFFER_FLUSH_PUT(rb) \
|
|
( \
|
|
(rb)->written++, \
|
|
(rb)->write_i = ((rb)->write_i + 1U) % ZB_RING_BUFFER_CAPACITY(rb) \
|
|
)
|
|
|
|
#define ZB_RING_BUFFER_FLUSH_PUT_HEAD(rb) \
|
|
do \
|
|
{ \
|
|
(rb)->written++; \
|
|
if ((rb)->read_i > 0U) \
|
|
{ \
|
|
--((rb)->read_i); \
|
|
} \
|
|
else \
|
|
{ \
|
|
(rb)->read_i = ZB_RING_BUFFER_CAPACITY(rb) - 1U; \
|
|
} \
|
|
} while(ZB_FALSE)
|
|
|
|
|
|
|
|
/**
|
|
Return amount of data which can be put into ring buffer tail starting from write_i
|
|
|
|
@param rb - ring buffer pointer
|
|
@param size - requested data size
|
|
*/
|
|
#define ZB_RING_BUFFER_LINEAR_PORTION(rb, size) \
|
|
( \
|
|
ZB_RING_BUFFER_CAPACITY(rb) - (rb)->write_i < size ? \
|
|
ZB_RING_BUFFER_CAPACITY(rb) - (rb)->write_i : size \
|
|
)
|
|
|
|
/**
|
|
Return amount of data which can be put into ring buffer tail starting from write_i using external rb capacity
|
|
|
|
@param rb - ring buffer pointer
|
|
@param size - requested data size
|
|
*/
|
|
#define ZB_RING_BUFFER_LINEAR_PORTION_BY_CAP(rb, size, rb_cap) \
|
|
( \
|
|
(rb_cap) - (rb)->write_i < (size) ? \
|
|
(rb_cap) - (rb)->write_i : (size) \
|
|
)
|
|
|
|
/**
|
|
* Get the size of available for writing continuous portion in ring buffer.
|
|
*
|
|
* That portion is from write_i index to the end of the buffer or
|
|
* from write_i index to the beginning of previously written but still not read data
|
|
*
|
|
* @param buf - ring buffer pointer
|
|
* @return size of available continuous portion
|
|
*/
|
|
#define ZB_RING_BUFFER_AVAILABLE_CONTINUOUS_PORTION(rb) \
|
|
ZB_RING_BUFFER_LINEAR_PORTION((rb), ZB_RING_BUFFER_FREE_SPACE(rb))
|
|
|
|
/**
|
|
Batch put data into ringbuffer
|
|
|
|
To be used to copy from external buffer to ring buffer
|
|
|
|
@param rb - ring buffer pointer
|
|
@param data - data ptr
|
|
@param size - requested data size
|
|
@param entries_written - (out) amount of data put
|
|
*/
|
|
#define ZB_RING_BUFFER_BATCH_PUT(rb, data, size, entries_written) \
|
|
do \
|
|
{ \
|
|
(entries_written) = ZB_RING_BUFFER_LINEAR_PORTION((rb), (size)); \
|
|
ZB_MEMCPY((rb)->ring_buf + (rb)->write_i, (data), (entries_written)); \
|
|
(rb)->written += (entries_written); \
|
|
(rb)->write_i = (((rb)->write_i + (entries_written)) % ZB_RING_BUFFER_CAPACITY(rb)); \
|
|
} while(ZB_FALSE)
|
|
|
|
/**
|
|
Batch put data into ringbuffer using external rb capacity
|
|
|
|
To be used to copy from external buffer to ring buffer
|
|
|
|
@param rb - ring buffer pointer
|
|
@param data - data ptr
|
|
@param size - requested data size
|
|
@param entries_written - (out) amount of data put
|
|
@param rb_cap - cap of the ring buffer
|
|
*/
|
|
#define ZB_RING_BUFFER_BATCH_PUT_BY_CAP(rb, data, size, entries_written, rb_cap) \
|
|
do \
|
|
{ \
|
|
(entries_written) = ZB_RING_BUFFER_LINEAR_PORTION_BY_CAP((rb), (size), (rb_cap)); \
|
|
ZB_MEMCPY((rb)->ring_buf + (rb)->write_i, (data), (entries_written)); \
|
|
(rb)->written += (entries_written); \
|
|
(rb)->write_i = (((rb)->write_i + (entries_written)) % (rb_cap)); \
|
|
} while(ZB_FALSE)
|
|
|
|
|
|
/**
|
|
* Flush after put more then 1 element to the ring buffer
|
|
*
|
|
* Do not check for write_i overflow!
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
* @param size - number of items put
|
|
* @return nothing
|
|
*/
|
|
#define ZB_RING_BUFFER_FLUSH_BATCH_PUT(rb, size) \
|
|
( \
|
|
(rb)->written += size, \
|
|
(rb)->write_i = (((rb)->write_i) + size) % ZB_RING_BUFFER_CAPACITY(rb) \
|
|
)
|
|
|
|
|
|
/**
|
|
* Put value to the ring buffer.
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
* @param value - value to put to ring buffer
|
|
* @return nothing
|
|
*/
|
|
#define ZB_RING_BUFFER_PUT(rb, value) \
|
|
( \
|
|
(rb)->ring_buf[(rb)->write_i] = (value), \
|
|
(rb)->written++, \
|
|
(rb)->write_i = ((rb)->write_i + 1U) % ZB_RING_BUFFER_CAPACITY(rb) \
|
|
)
|
|
|
|
|
|
/**
|
|
* Put value to the ring buffer using memcpy.
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
* @param value_ptr - pointer to value to put to ring buffer
|
|
* @return nothing
|
|
*/
|
|
#define ZB_RING_BUFFER_PUT_PTR(rb, value_ptr) \
|
|
( \
|
|
memcpy(&((rb)->ring_buf[(rb)->write_i]), (value_ptr), sizeof((rb)->ring_buf[0])), \
|
|
(rb)->written++, \
|
|
(rb)->write_i = ((rb)->write_i + 1U) % ZB_RING_BUFFER_CAPACITY(rb) \
|
|
)
|
|
|
|
|
|
/**
|
|
* Reinsert last value into the ring buffer using memcpy.
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
* @param value_ptr - pointer to value to put to ring buffer
|
|
* @return nothing
|
|
*/
|
|
#define ZB_RING_BUFFER_PUT_REUSE_LAST(rb, value_ptr) \
|
|
( \
|
|
memcpy(&((rb)->ring_buf[((rb)->write_i ? (rb)->write_i - 1U : (rb)->write_i + ZB_RING_BUFFER_CAPACITY(rb) - 1U)]), \
|
|
(value_ptr), \
|
|
sizeof((rb)->ring_buf[0])) \
|
|
)
|
|
|
|
|
|
/**
|
|
* Get entry from the ring buffer read pointer position
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
*
|
|
* @return pointer to the ring buffer entry or NULL if it is empty
|
|
*/
|
|
#define ZB_RING_BUFFER_PEEK(rb) \
|
|
( \
|
|
ZB_RING_BUFFER_IS_EMPTY(rb) ? NULL \
|
|
: (rb)->ring_buf + (rb)->read_i \
|
|
)
|
|
|
|
/**
|
|
* Get entry from the ring buffer read pointer position
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
*
|
|
* @return pointer to the ring buffer entry
|
|
*/
|
|
#define ZB_RING_BUFFER_GET(rb) \
|
|
( \
|
|
(rb)->ring_buf + (rb)->read_i \
|
|
)
|
|
|
|
/**
|
|
* Get entry from the ring buffer write pointer position
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
*
|
|
* @return pointer to the ring buffer entry
|
|
*/
|
|
#define ZB_RING_BUFFER_GETW(rb) \
|
|
( (rb)->ring_buf + (rb)->write_i )
|
|
|
|
/**
|
|
* Move ring buffer read pointer.
|
|
*
|
|
* To be used after ZB_RING_BUFFER_PEEK().
|
|
* @note This macro does not check for an empty ring buffer.
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
* @return nothing
|
|
*/
|
|
#define ZB_RING_BUFFER_FLUSH_GET(rb) \
|
|
( \
|
|
(rb)->written--, \
|
|
((rb)->read_i = ((rb)->read_i + 1U) % ZB_RING_BUFFER_CAPACITY(rb)) \
|
|
)
|
|
|
|
|
|
/**
|
|
* Get entries from the ring buffer read pointer position which can be get at once
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
* @param size - (out) number of entries which can be got
|
|
*
|
|
* @return pointer to the ring buffer entry
|
|
*/
|
|
#define ZB_RING_BUFFER_GET_BATCH(rb, size) \
|
|
( \
|
|
(size) = ((rb)->written <= (ZB_RING_BUFFER_CAPACITY(rb) - (rb)->read_i) \
|
|
? \
|
|
(rb)->written \
|
|
: \
|
|
(ZB_RING_BUFFER_CAPACITY(rb) - (rb)->read_i)), \
|
|
(rb)->ring_buf + (rb)->read_i \
|
|
) \
|
|
|
|
|
|
|
|
/**
|
|
* Move ring buffer read pointer for more than 1 element
|
|
*
|
|
* @note This macro does not check for empty ring buffer.
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
* @param size - number of elements to mark as read
|
|
* @return nothing
|
|
*/
|
|
#define ZB_RING_BUFFER_FLUSH_GET_BATCH(rb, size) \
|
|
( \
|
|
(rb)->written -= (size), \
|
|
((rb)->read_i = ((rb)->read_i + (size)) % ZB_RING_BUFFER_CAPACITY((rb))) \
|
|
)
|
|
|
|
/**
|
|
* Move ring buffer's read and write pointers to the specified pos
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
* @param b - new position of read_i buffer's pointer
|
|
* @param e - new position of write_i buffer's pointer
|
|
* @return nothing
|
|
*/
|
|
#define ZB_RING_BUFFER_LOCATE(rb, b, e) \
|
|
( (rb)->read_i = b, \
|
|
(rb)->write_i = e, \
|
|
(rb)->written = e - b \
|
|
)
|
|
|
|
/**
|
|
* Returns number of used entries
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
*/
|
|
|
|
#define ZB_RING_BUFFER_USED_SPACE(rb) \
|
|
( \
|
|
(rb)->written \
|
|
)
|
|
|
|
#define ZB_RING_BUFFER_SEARCH_GET(_rb, _i) \
|
|
( \
|
|
ZB_RING_BUFFER_IS_EMPTY(_rb) ? NULL \
|
|
: (_rb)->ring_buf + ((_rb)->read_i +(_i)) % ZB_RING_BUFFER_CAPACITY(_rb) \
|
|
)
|
|
|
|
|
|
/**
|
|
* This is a fake type used for type casting.
|
|
* Represents array of bytes, used for serial trace e.t.c.
|
|
*
|
|
* @Example:
|
|
* @code
|
|
* ZB_RING_BUFFER_DECLARE(sniffer_io_buffer, zb_uint8_t, 4096);
|
|
* ...
|
|
* zb_osif_set_user_io_buffer((zb_byte_array_t*)&gs_sniffer_io_buf, 4096);
|
|
* @endcode
|
|
*/
|
|
ZB_RING_BUFFER_DECLARE(zb_byte_array, zb_uint8_t, 1);
|
|
|
|
/**
|
|
* @see ZB_RING_BUFFER_IS_EMPTY
|
|
*/
|
|
#define ZB_BYTE_ARRAY_IS_EMPTY(rb) ZB_RING_BUFFER_IS_EMPTY(rb)
|
|
|
|
/**
|
|
* @see ZB_RING_BUFFER_PEEK
|
|
*/
|
|
#define ZB_BYTE_ARRAY_PEEK(rb) ZB_RING_BUFFER_PEEK(rb)
|
|
|
|
/**
|
|
* Return 1 if ring buffer is full
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
* @param cap - ring buffer capacity (number of bytes)
|
|
*/
|
|
#define ZB_BYTE_ARRAY_IS_FULL(rb, cap) ((zb_uint_t)(rb)->written >= cap)
|
|
|
|
/**
|
|
* Move ring buffer read pointer.
|
|
*
|
|
* To be used after ZB_BYTE_ARRAY_PEEK().
|
|
* @note This macro does not check for empty ring buffer.
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
* @param cap - ring buffer capacity (number of bytes)
|
|
* @return nothing
|
|
*/
|
|
#define ZB_BYTE_ARRAY_FLUSH_GET(rb, cap) \
|
|
( \
|
|
(rb)->written--, \
|
|
((rb)->read_i = ((rb)->read_i + 1U) % (cap)) \
|
|
)
|
|
|
|
/* 10/04/17 CR Ustimenko start */
|
|
/**
|
|
* Get entries from the ring buffer read pointer position which can be get at once
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
* @param size - (out) number of entries which can be got
|
|
* @param cap - ring buffer capacity (number of bytes)
|
|
*
|
|
* @return pointer to the ring buffer entry
|
|
*/
|
|
#define ZB_BYTE_ARRAY_GET_BATCH(rb, size, cap) \
|
|
( \
|
|
size = ((rb)->written <= (cap - (rb)->read_i) \
|
|
? \
|
|
(rb)->written \
|
|
: \
|
|
(cap - (rb)->read_i)), \
|
|
(rb)->ring_buf + (rb)->read_i \
|
|
)
|
|
|
|
/**
|
|
* Move ring buffer read pointer for more than 1 element
|
|
*
|
|
* This macro does not check for an empty ring buffer.
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
* @param size - number of elements to mark as read
|
|
* @param cap - ring buffer capacity (number of bytes)
|
|
* @return nothing
|
|
*/
|
|
#define ZB_BYTE_ARRAY_FLUSH_GET_BATCH(rb, size, cap) \
|
|
( \
|
|
(rb)->written -= size, \
|
|
((rb)->read_i = ((rb)->read_i + size) % cap) \
|
|
)
|
|
/* 10/04/17 CR Ustimenko end */
|
|
|
|
/**
|
|
* Put value to the ring buffer.
|
|
*
|
|
* @param rb - ring buffer pointer.
|
|
* @param value - value to put to ring buffer
|
|
* @param cap - ring buffer capacity (number of bytes)
|
|
* @return nothing
|
|
*/
|
|
#define ZB_BYTE_ARRAY_PUT(rb, value, cap) \
|
|
( \
|
|
(rb)->ring_buf[(rb)->write_i] = (value), \
|
|
(rb)->written++, \
|
|
(rb)->write_i = ((rb)->write_i + 1U) % cap \
|
|
)
|
|
|
|
#define ZB_BYTE_ARRAY_PUT_HEAD_RESERVE_IDX(rb, cap) \
|
|
( \
|
|
((rb)->read_i > 0U) ? \
|
|
((rb)->read_i - 1U) : ((cap) - 1U) \
|
|
)
|
|
|
|
#define ZB_BYTE_ARRAY_PUT_HEAD_RESERVE(rb, cap) \
|
|
( \
|
|
((rb)->ring_buf + ZB_BYTE_ARRAY_PUT_HEAD_RESERVE_IDX(rb, (cap))) \
|
|
)
|
|
|
|
#define ZB_BYTE_ARRAY_FLUSH_PUT_HEAD(rb, cap) \
|
|
do \
|
|
{ \
|
|
(rb)->written++; \
|
|
if ((rb)->read_i > 0U) \
|
|
{ \
|
|
--((rb)->read_i); \
|
|
} \
|
|
else \
|
|
{ \
|
|
(rb)->read_i = (cap) - 1U; \
|
|
} \
|
|
} while(ZB_FALSE)
|
|
|
|
#define ZB_BYTE_ARRAY_FLUSH_PUT(rb, cap) \
|
|
( \
|
|
(rb)->written++, \
|
|
(rb)->write_i = ((rb)->write_i + 1U) % (cap) \
|
|
)
|
|
|
|
/*! @} */
|
|
/*! @endcond */
|
|
|
|
#endif /* ZB_RINGBUFFER_H */
|