|
|
@@ -57,7 +57,8 @@ static inline void _ff_unlock(tu_fifo_mutex_t mutex)
|
|
|
#endif
|
|
|
|
|
|
/** \enum tu_fifo_copy_mode_t
|
|
|
- * \brief Write modes intended to allow special read and write functions to be able to copy data to and from USB hardware FIFOs as needed for e.g. STM32s and others
|
|
|
+ * \brief Write modes intended to allow special read and write functions to be able to
|
|
|
+ * copy data to and from USB hardware FIFOs as needed for e.g. STM32s and others
|
|
|
*/
|
|
|
typedef enum
|
|
|
{
|
|
|
@@ -77,7 +78,10 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si
|
|
|
f->item_size = item_size;
|
|
|
f->overwritable = overwritable;
|
|
|
|
|
|
- f->max_pointer_idx = 2*depth - 1; // Limit index space to 2*depth - this allows for a fast "modulo" calculation but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable only if overflow happens once (important for unsupervised DMA applications)
|
|
|
+ // Limit index space to 2*depth - this allows for a fast "modulo" calculation
|
|
|
+ // but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable
|
|
|
+ // only if overflow happens once (important for unsupervised DMA applications)
|
|
|
+ f->max_pointer_idx = 2*depth - 1;
|
|
|
f->non_used_index_space = UINT16_MAX - f->max_pointer_idx;
|
|
|
|
|
|
f->rd_idx = f->wr_idx = 0;
|
|
|
@@ -319,7 +323,8 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu
|
|
|
static uint16_t advance_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset)
|
|
|
{
|
|
|
// We limit the index space of p such that a correct wrap around happens
|
|
|
- // Check for a wrap around or if we are in unused index space - This has to be checked first!! We are exploiting the wrap around to the correct index
|
|
|
+ // Check for a wrap around or if we are in unused index space - This has to be checked first!!
|
|
|
+ // We are exploiting the wrap around to the correct index
|
|
|
if ((p > p + offset) || (p + offset > f->max_pointer_idx))
|
|
|
{
|
|
|
p = (p + offset) + f->non_used_index_space;
|
|
|
@@ -335,7 +340,8 @@ static uint16_t advance_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset)
|
|
|
static uint16_t backward_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset)
|
|
|
{
|
|
|
// We limit the index space of p such that a correct wrap around happens
|
|
|
- // Check for a wrap around or if we are in unused index space - This has to be checked first!! We are exploiting the wrap around to the correct index
|
|
|
+ // Check for a wrap around or if we are in unused index space - This has to be checked first!!
|
|
|
+ // We are exploiting the wrap around to the correct index
|
|
|
if ((p < p - offset) || (p - offset > f->max_pointer_idx))
|
|
|
{
|
|
|
p = (p - offset) - f->non_used_index_space;
|
|
|
@@ -348,9 +354,9 @@ static uint16_t backward_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset)
|
|
|
}
|
|
|
|
|
|
// get relative from absolute pointer
|
|
|
-static uint16_t get_relative_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset)
|
|
|
+static uint16_t get_relative_pointer(tu_fifo_t* f, uint16_t p)
|
|
|
{
|
|
|
- return _ff_mod(advance_pointer(f, p, offset), f->depth);
|
|
|
+ return _ff_mod(p, f->depth);
|
|
|
}
|
|
|
|
|
|
// Works on local copies of w and r - return only the difference and as such can be used to determine an overflow
|
|
|
@@ -396,7 +402,7 @@ static inline void _tu_fifo_correct_read_pointer(tu_fifo_t* f, uint16_t wAbs)
|
|
|
|
|
|
// Works on local copies of w and r
|
|
|
// Must be protected by mutexes since in case of an overflow read pointer gets modified
|
|
|
-static bool _tu_fifo_peek_at(tu_fifo_t* f, uint16_t offset, void * p_buffer, uint16_t wAbs, uint16_t rAbs)
|
|
|
+static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wAbs, uint16_t rAbs)
|
|
|
{
|
|
|
uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs);
|
|
|
|
|
|
@@ -408,9 +414,9 @@ static bool _tu_fifo_peek_at(tu_fifo_t* f, uint16_t offset, void * p_buffer, uin
|
|
|
}
|
|
|
|
|
|
// Skip beginning of buffer
|
|
|
- if (cnt == 0 || offset >= cnt) return false;
|
|
|
+ if (cnt == 0) return false;
|
|
|
|
|
|
- uint16_t rRel = get_relative_pointer(f, rAbs, offset);
|
|
|
+ uint16_t rRel = get_relative_pointer(f, rAbs);
|
|
|
|
|
|
// Peek data
|
|
|
_ff_pull(f, p_buffer, rRel);
|
|
|
@@ -420,7 +426,7 @@ static bool _tu_fifo_peek_at(tu_fifo_t* f, uint16_t offset, void * p_buffer, uin
|
|
|
|
|
|
// Works on local copies of w and r
|
|
|
// Must be protected by mutexes since in case of an overflow read pointer gets modified
|
|
|
-static uint16_t _tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffer, uint16_t n, uint16_t wAbs, uint16_t rAbs, tu_fifo_copy_mode_t copy_mode)
|
|
|
+static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t wAbs, uint16_t rAbs, tu_fifo_copy_mode_t copy_mode)
|
|
|
{
|
|
|
uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs);
|
|
|
|
|
|
@@ -433,13 +439,12 @@ static uint16_t _tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffe
|
|
|
}
|
|
|
|
|
|
// Skip beginning of buffer
|
|
|
- if (cnt == 0 || offset >= cnt) return 0;
|
|
|
+ if (cnt == 0) return 0;
|
|
|
|
|
|
// Check if we can read something at and after offset - if too less is available we read what remains
|
|
|
- cnt -= offset;
|
|
|
if (cnt < n) n = cnt;
|
|
|
|
|
|
- uint16_t rRel = get_relative_pointer(f, rAbs, offset);
|
|
|
+ uint16_t rRel = get_relative_pointer(f, rAbs);
|
|
|
|
|
|
// Peek data
|
|
|
_ff_pull_n(f, p_buffer, n, rRel, copy_mode);
|
|
|
@@ -479,7 +484,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu
|
|
|
w = r;
|
|
|
}
|
|
|
|
|
|
- uint16_t wRel = get_relative_pointer(f, w, 0);
|
|
|
+ uint16_t wRel = get_relative_pointer(f, w);
|
|
|
|
|
|
// Write data
|
|
|
_ff_push_n(f, buf8, n, wRel, copy_mode);
|
|
|
@@ -497,7 +502,8 @@ static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo
|
|
|
_ff_lock(f->mutex_rd);
|
|
|
|
|
|
// Peek the data
|
|
|
- n = _tu_fifo_peek_at_n(f, 0, buffer, n, f->wr_idx, f->rd_idx, copy_mode); // f->rd_idx might get modified in case of an overflow so we can not use a local variable
|
|
|
+ // f->rd_idx might get modified in case of an overflow so we can not use a local variable
|
|
|
+ n = _tu_fifo_peek_n(f, buffer, n, f->wr_idx, f->rd_idx, copy_mode);
|
|
|
|
|
|
// Advance read pointer
|
|
|
f->rd_idx = advance_pointer(f, f->rd_idx, n);
|
|
|
@@ -635,7 +641,8 @@ bool tu_fifo_read(tu_fifo_t* f, void * buffer)
|
|
|
_ff_lock(f->mutex_rd);
|
|
|
|
|
|
// Peek the data
|
|
|
- bool ret = _tu_fifo_peek_at(f, 0, buffer, f->wr_idx, f->rd_idx); // f->rd_idx might get modified in case of an overflow so we can not use a local variable
|
|
|
+ // f->rd_idx might get modified in case of an overflow so we can not use a local variable
|
|
|
+ bool ret = _tu_fifo_peek(f, buffer, f->wr_idx, f->rd_idx);
|
|
|
|
|
|
// Advance pointer
|
|
|
f->rd_idx = advance_pointer(f, f->rd_idx, ret);
|
|
|
@@ -685,10 +692,10 @@ uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t* f, void * buffer, uint1
|
|
|
@returns TRUE if the queue is not empty
|
|
|
*/
|
|
|
/******************************************************************************/
|
|
|
-bool tu_fifo_peek_at(tu_fifo_t* f, uint16_t offset, void * p_buffer)
|
|
|
+bool tu_fifo_peek(tu_fifo_t* f, void * p_buffer)
|
|
|
{
|
|
|
_ff_lock(f->mutex_rd);
|
|
|
- bool ret = _tu_fifo_peek_at(f, offset, p_buffer, f->wr_idx, f->rd_idx);
|
|
|
+ bool ret = _tu_fifo_peek(f, p_buffer, f->wr_idx, f->rd_idx);
|
|
|
_ff_unlock(f->mutex_rd);
|
|
|
return ret;
|
|
|
}
|
|
|
@@ -700,8 +707,6 @@ bool tu_fifo_peek_at(tu_fifo_t* f, uint16_t offset, void * p_buffer)
|
|
|
|
|
|
@param[in] f
|
|
|
Pointer to the FIFO buffer to manipulate
|
|
|
- @param[in] offset
|
|
|
- Position to read from in the FIFO buffer with respect to read pointer
|
|
|
@param[in] p_buffer
|
|
|
Pointer to the place holder for data read from the buffer
|
|
|
@param[in] n
|
|
|
@@ -710,10 +715,10 @@ bool tu_fifo_peek_at(tu_fifo_t* f, uint16_t offset, void * p_buffer)
|
|
|
@returns Number of bytes written to p_buffer
|
|
|
*/
|
|
|
/******************************************************************************/
|
|
|
-uint16_t tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffer, uint16_t n)
|
|
|
+uint16_t tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n)
|
|
|
{
|
|
|
_ff_lock(f->mutex_rd);
|
|
|
- bool ret = _tu_fifo_peek_at_n(f, offset, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_COPY_INC);
|
|
|
+ bool ret = _tu_fifo_peek_n(f, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_COPY_INC);
|
|
|
_ff_unlock(f->mutex_rd);
|
|
|
return ret;
|
|
|
}
|
|
|
@@ -742,7 +747,7 @@ bool tu_fifo_write(tu_fifo_t* f, const void * data)
|
|
|
|
|
|
if ( _tu_fifo_full(f, w, f->rd_idx) && !f->overwritable ) return false;
|
|
|
|
|
|
- uint16_t wRel = get_relative_pointer(f, w, 0);
|
|
|
+ uint16_t wRel = get_relative_pointer(f, w);
|
|
|
|
|
|
// Write data
|
|
|
_ff_push(f, data, wRel);
|
|
|
@@ -883,36 +888,27 @@ void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n)
|
|
|
|
|
|
/******************************************************************************/
|
|
|
/*!
|
|
|
- @brief Get linear read info
|
|
|
+ @brief Get read info
|
|
|
|
|
|
Returns the length and pointer from which bytes can be read in a linear manner.
|
|
|
This is of major interest for DMA transmissions. If returned length is zero the
|
|
|
- corresponding pointer is invalid. The returned length is limited to the number
|
|
|
- of ITEMS n which the user wants to write into the buffer.
|
|
|
- The write pointer does NOT get advanced, use tu_fifo_advance_read_pointer() to
|
|
|
- do so! If the length returned is less than n i.e. len<n, then a wrap occurs
|
|
|
- and you need to execute this function a second time to get a pointer to the
|
|
|
- wrapped part!
|
|
|
+ corresponding pointer is invalid.
|
|
|
+ The read pointer does NOT get advanced, use tu_fifo_advance_read_pointer() to
|
|
|
+ do so!
|
|
|
@param[in] f
|
|
|
Pointer to FIFO
|
|
|
- @param[in] offset
|
|
|
- Number of ITEMS to ignore before start writing
|
|
|
- @param[out] **ptr
|
|
|
- Pointer to start writing to
|
|
|
- @param[in] n
|
|
|
- Number of ITEMS to read from buffer
|
|
|
- @return len
|
|
|
- Length of linear part IN ITEMS, if zero corresponding pointer ptr is invalid
|
|
|
+ @param[out] *info
|
|
|
+ Pointer to struct which holds the desired infos
|
|
|
*/
|
|
|
/******************************************************************************/
|
|
|
-uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr, uint16_t n)
|
|
|
+void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info)
|
|
|
{
|
|
|
// Operate on temporary values in case they change in between
|
|
|
uint16_t w = f->wr_idx, r = f->rd_idx;
|
|
|
|
|
|
uint16_t cnt = _tu_fifo_count(f, w, r);
|
|
|
|
|
|
- // Check overflow and correct if required
|
|
|
+ // Check overflow and correct if required - may happen in case a DMA wrote too fast
|
|
|
if (cnt > f->depth)
|
|
|
{
|
|
|
_ff_lock(f->mutex_rd);
|
|
|
@@ -922,104 +918,85 @@ uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr,
|
|
|
cnt = f->depth;
|
|
|
}
|
|
|
|
|
|
- // Skip beginning of buffer
|
|
|
- if (cnt == 0 || offset >= cnt) return 0;
|
|
|
-
|
|
|
- // Check if we can read something at and after offset - if too less is available we read what remains
|
|
|
- cnt -= offset;
|
|
|
- if (cnt < n) n = cnt;
|
|
|
+ // Check if fifo is empty
|
|
|
+ if (cnt == 0)
|
|
|
+ {
|
|
|
+ info->len_lin = 0;
|
|
|
+ info->len_wrap = 0;
|
|
|
+ info->ptr_lin = NULL;
|
|
|
+ info->ptr_wrap = NULL;
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
// Get relative pointers
|
|
|
- w = get_relative_pointer(f, w, 0);
|
|
|
- r = get_relative_pointer(f, r, offset);
|
|
|
+ w = get_relative_pointer(f, w);
|
|
|
+ r = get_relative_pointer(f, r);
|
|
|
|
|
|
- // Check if there is a wrap around necessary
|
|
|
- uint16_t len;
|
|
|
+ // Copy pointer to buffer to start reading from
|
|
|
+ info->ptr_lin = &f->buffer[r];
|
|
|
|
|
|
+ // Check if there is a wrap around necessary
|
|
|
if (w > r) {
|
|
|
- len = w - r;
|
|
|
+ // Non wrapping case
|
|
|
+ info->len_lin = cnt;
|
|
|
+ info->len_wrap = 0;
|
|
|
+ info->ptr_wrap = NULL;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- len = f->depth - r; // Also the case if FIFO was full
|
|
|
+ info->len_lin = f->depth - r; // Also the case if FIFO was full
|
|
|
+ info->len_wrap = cnt - info->len_lin;
|
|
|
+ info->ptr_wrap = f->buffer;
|
|
|
}
|
|
|
-
|
|
|
- // Limit to required length
|
|
|
- len = tu_min16(n, len);
|
|
|
-
|
|
|
- // Copy pointer to buffer to start reading from
|
|
|
- *ptr = &f->buffer[r];
|
|
|
-
|
|
|
- return len;
|
|
|
}
|
|
|
|
|
|
/******************************************************************************/
|
|
|
/*!
|
|
|
@brief Get linear write info
|
|
|
|
|
|
- Returns the length and pointer from which bytes can be written into buffer array in a linear manner.
|
|
|
- This is of major interest for DMA transmissions not using circular mode. If returned length is zero the
|
|
|
- corresponding pointer is invalid. The returned length is limited to the number of BYTES n which the user
|
|
|
- wants to write into the buffer.
|
|
|
- The write pointer does NOT get advanced, use tu_fifo_advance_write_pointer() to do so! If the length
|
|
|
- returned is less than n i.e. len<n, then a wrap occurs and you need to execute this function a second
|
|
|
- time to get a pointer to the wrapped part!
|
|
|
+ Returns the length and pointer to which bytes can be written into FIFO in a linear manner.
|
|
|
+ This is of major interest for DMA transmissions not using circular mode. If a returned length is zero the
|
|
|
+ corresponding pointer is invalid. The returned lengths summed up are the currently free space in the FIFO.
|
|
|
+ The write pointer does NOT get advanced, use tu_fifo_advance_write_pointer() to do so!
|
|
|
+ TAKE CARE TO NOT OVERFLOW THE BUFFER MORE THAN TWO TIMES THE FIFO DEPTH - IT CAN NOT RECOVERE OTHERWISE!
|
|
|
@param[in] f
|
|
|
Pointer to FIFO
|
|
|
- @param[in] offset
|
|
|
- Number of ITEMS to ignore before start writing
|
|
|
- @param[out] **ptr
|
|
|
- Pointer to start writing to
|
|
|
- @param[in] n
|
|
|
- Number of ITEMS to write into buffer
|
|
|
- @return len
|
|
|
- Length of linear part IN ITEMS, if zero corresponding pointer ptr is invalid
|
|
|
+ @param[out] *info
|
|
|
+ Pointer to struct which holds the desired infos
|
|
|
*/
|
|
|
/******************************************************************************/
|
|
|
-uint16_t tu_fifo_get_linear_write_info(tu_fifo_t *f, uint16_t offset, void **ptr, uint16_t n)
|
|
|
+void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info)
|
|
|
{
|
|
|
uint16_t w = f->wr_idx, r = f->rd_idx;
|
|
|
uint16_t free = _tu_fifo_remaining(f, w, r);
|
|
|
|
|
|
- if (!f->overwritable)
|
|
|
+ if (free == 0)
|
|
|
{
|
|
|
- // Not overwritable limit up to full
|
|
|
- n = tu_min16(n, free);
|
|
|
- }
|
|
|
- else if (n >= f->depth)
|
|
|
- {
|
|
|
- // If overwrite is allowed it must be less than or equal to 2 x buffer length, otherwise the overflow can not be resolved by the read functions
|
|
|
- TU_VERIFY(n <= 2*f->depth);
|
|
|
-
|
|
|
- n = f->depth;
|
|
|
- // We start writing at the read pointer's position since we fill the complete
|
|
|
- // buffer and we do not want to modify the read pointer within a write function!
|
|
|
- // This would end up in a race condition with read functions!
|
|
|
- w = r;
|
|
|
+ info->len_lin = 0;
|
|
|
+ info->len_wrap = 0;
|
|
|
+ info->ptr_lin = NULL;
|
|
|
+ info->ptr_wrap = NULL;
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
- // Check if there is room to write to
|
|
|
- if (free == 0 || offset >= free) return 0;
|
|
|
-
|
|
|
// Get relative pointers
|
|
|
- w = get_relative_pointer(f, w, offset);
|
|
|
- r = get_relative_pointer(f, r, 0);
|
|
|
- uint16_t len;
|
|
|
+ w = get_relative_pointer(f, w);
|
|
|
+ r = get_relative_pointer(f, r);
|
|
|
+
|
|
|
+ // Copy pointer to buffer to start writing to
|
|
|
+ info->ptr_lin = &f->buffer[w];
|
|
|
|
|
|
if (w < r)
|
|
|
{
|
|
|
- len = r-w;
|
|
|
+ // Non wrapping case
|
|
|
+ info->len_lin = r-w;
|
|
|
+ info->len_wrap = 0;
|
|
|
+ info->ptr_wrap = NULL;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- len = f->depth - w;
|
|
|
+ info->len_lin = f->depth - w;
|
|
|
+ info->len_wrap = free - info->len_lin; // Remaining length - n already was limited to free or FIFO depth
|
|
|
+ info->ptr_wrap = f->buffer; // Always start of buffer
|
|
|
}
|
|
|
-
|
|
|
- // Limit to required length
|
|
|
- len = tu_min16(n, len);
|
|
|
-
|
|
|
- // Copy pointer to buffer to start reading from
|
|
|
- *ptr = &f->buffer[w];
|
|
|
-
|
|
|
- return len;
|
|
|
}
|