diff options
| author | Zixun LI <[email protected]> | 2025-11-27 12:01:33 +0100 |
|---|---|---|
| committer | Zixun LI <[email protected]> | 2025-11-27 12:01:33 +0100 |
| commit | 2e8d193c732bb211ebff8badff16a84775db42ff (patch) | |
| tree | 9a3410e65711df25559524b760447ff68fdd316a /src/common/tusb_fifo.c | |
| parent | b997ec725812d2f6a573610ba0dd817f271eddea (diff) | |
| parent | 5ef55bfa30d6f8cf175b3d327f621c76aae7b138 (diff) | |
Merge remote-tracking branch 'tinyusb/master' into hcd_fsdev
Signed-off-by: Zixun LI <[email protected]>
Diffstat (limited to 'src/common/tusb_fifo.c')
| -rw-r--r-- | src/common/tusb_fifo.c | 608 |
1 files changed, 169 insertions, 439 deletions
diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 5c9e586fb..27b97310a 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -38,35 +38,23 @@ #if OSAL_MUTEX_REQUIRED -TU_ATTR_ALWAYS_INLINE static inline void _ff_lock(osal_mutex_t mutex) { +TU_ATTR_ALWAYS_INLINE static inline void ff_lock(osal_mutex_t mutex) { if (mutex != NULL) { osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); } } -TU_ATTR_ALWAYS_INLINE static inline void _ff_unlock(osal_mutex_t mutex) { +TU_ATTR_ALWAYS_INLINE static inline void ff_unlock(osal_mutex_t mutex) { if (mutex != NULL) { osal_mutex_unlock(mutex); } } #else + #define ff_lock(_mutex) + #define ff_unlock(_mutex) -#define _ff_lock(_mutex) -#define _ff_unlock(_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 - */ -typedef enum { - TU_FIFO_COPY_INC, ///< Copy from/to an increasing source/destination address - default mode -#ifdef TUP_MEM_CONST_ADDR - TU_FIFO_COPY_CST_FULL_WORDS, ///< Copy from/to a constant source/destination address - required for e.g. STM32 to write into USB hardware FIFO #endif -} tu_fifo_copy_mode_t; bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_size, bool overwritable) { // Limit index space to 2*depth - this allows for a fast "modulo" calculation @@ -76,78 +64,67 @@ bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_si return false; } - _ff_lock(f->mutex_wr); - _ff_lock(f->mutex_rd); + ff_lock(f->mutex_wr); + ff_lock(f->mutex_rd); f->buffer = (uint8_t *)buffer; f->depth = depth; - f->item_size = (uint16_t)(item_size & 0x7FFF); + f->item_size = (uint16_t)(item_size & 0x7FFFu); f->overwritable = overwritable; - f->rd_idx = 0; - f->wr_idx = 0; + f->rd_idx = 0u; + f->wr_idx = 0u; - _ff_unlock(f->mutex_wr); - _ff_unlock(f->mutex_rd); + ff_unlock(f->mutex_wr); + ff_unlock(f->mutex_rd); return true; } //--------------------------------------------------------------------+ // Pull & Push +// copy data to/from fifo without updating read/write pointers //--------------------------------------------------------------------+ - -#ifdef TUP_MEM_CONST_ADDR -// Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address -// Code adapted from dcd_synopsys.c -// TODO generalize with configurable 1 byte or 4 byte each read -static void _ff_push_const_addr(uint8_t *ff_buf, const void *app_buf, uint16_t len) { - const volatile uint32_t *reg_rx = (volatile const uint32_t *)app_buf; - +#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 +// Copy to fifo from fixed address buffer (usually a rx register) with TU_FIFO_FIXED_ADDR_RW32 mode +static void ff_push_fixed_addr_rw32(uint8_t *ff_buf, const volatile uint32_t *reg_rx, uint16_t len) { // Reading full available 32 bit words from const app address uint16_t full_words = len >> 2; while (full_words--) { - tu_unaligned_write32(ff_buf, *reg_rx); + const uint32_t tmp32 = *reg_rx; + tu_unaligned_write32(ff_buf, tmp32); ff_buf += 4; } // Read the remaining 1-3 bytes from const app address const uint8_t bytes_rem = len & 0x03; if (bytes_rem) { - uint32_t tmp32 = *reg_rx; + const uint32_t tmp32 = *reg_rx; memcpy(ff_buf, &tmp32, bytes_rem); } } -// Intended to be used to write to hardware USB FIFO in e.g. STM32 -// where all data is written to a constant address in full word copies -static void _ff_pull_const_addr(void *app_buf, const uint8_t *ff_buf, uint16_t len) { - volatile uint32_t *reg_tx = (volatile uint32_t *)app_buf; - +// Copy from fifo to fixed address buffer (usually a tx register) with TU_FIFO_FIXED_ADDR_RW32 mode +static void ff_pull_fixed_addr_rw32(volatile uint32_t *reg_tx, const uint8_t *ff_buf, uint16_t len) { // Write full available 32 bit words to const address - uint16_t full_words = len >> 2; + uint16_t full_words = len >> 2u; while (full_words--) { *reg_tx = tu_unaligned_read32(ff_buf); - ff_buf += 4; + ff_buf += 4u; } - // Write the remaining 1-3 bytes into const address + // Write the remaining 1-3 bytes const uint8_t bytes_rem = len & 0x03; if (bytes_rem) { - uint32_t tmp32 = 0; + uint32_t tmp32 = 0u; memcpy(&tmp32, ff_buf, bytes_rem); - *reg_tx = tmp32; } } #endif -// send one item to fifo WITHOUT updating write pointer -static inline void _ff_push(tu_fifo_t *f, const void *app_buf, uint16_t rel) { - memcpy(f->buffer + (rel * f->item_size), app_buf, f->item_size); -} - // send n items to fifo WITHOUT updating write pointer -static void _ff_push_n(tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr, tu_fifo_copy_mode_t copy_mode) { +static void ff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr, + tu_fifo_access_mode_t copy_mode) { const uint16_t lin_count = f->depth - wr_ptr; const uint16_t wrap_count = n - lin_count; @@ -158,67 +135,51 @@ static void _ff_push_n(tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t w uint8_t *ff_buf = f->buffer + (wr_ptr * f->item_size); switch (copy_mode) { - case TU_FIFO_COPY_INC: + case TU_FIFO_INC_ADDR_RW8: if (n <= lin_count) { // Linear only memcpy(ff_buf, app_buf, n * f->item_size); } else { // Wrap around - - // Write data to linear part of buffer - memcpy(ff_buf, app_buf, lin_bytes); - - // Write data wrapped around - // TU_ASSERT(nWrap_bytes <= f->depth, ); - memcpy(f->buffer, ((const uint8_t *)app_buf) + lin_bytes, wrap_bytes); + memcpy(ff_buf, app_buf, lin_bytes); // linear part + memcpy(f->buffer, ((const uint8_t *)app_buf) + lin_bytes, wrap_bytes); // wrapped part } break; -#ifdef TUP_MEM_CONST_ADDR - case TU_FIFO_COPY_CST_FULL_WORDS: - // Intended for hardware buffers from which it can be read word by word only +#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 + case TU_FIFO_FIXED_ADDR_RW32: { + const volatile uint32_t *reg_rx = (volatile const uint32_t *)app_buf; if (n <= lin_count) { // Linear only - _ff_push_const_addr(ff_buf, app_buf, n * f->item_size); + ff_push_fixed_addr_rw32(ff_buf, reg_rx, n * f->item_size); } else { - // Wrap around case + // Wrap around // Write full words to linear part of buffer - uint16_t nLin_4n_bytes = lin_bytes & 0xFFFC; - _ff_push_const_addr(ff_buf, app_buf, nLin_4n_bytes); - ff_buf += nLin_4n_bytes; + uint16_t lin_4n_bytes = lin_bytes & 0xFFFC; + ff_push_fixed_addr_rw32(ff_buf, reg_rx, lin_4n_bytes); + ff_buf += lin_4n_bytes; // There could be odd 1-3 bytes before the wrap-around boundary - uint8_t rem = lin_bytes & 0x03; + const uint8_t rem = lin_bytes & 0x03; if (rem > 0) { - const volatile uint32_t *rx_fifo = (volatile const uint32_t *)app_buf; + const uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem); + const uint32_t tmp32 = *reg_rx; + tu_scatter_write32(tmp32, ff_buf, rem, f->buffer, remrem); - uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem); wrap_bytes -= remrem; - - uint32_t tmp32 = *rx_fifo; - uint8_t *src_u8 = ((uint8_t *)&tmp32); - - // Write 1-3 bytes before wrapped boundary - while (rem--) { - *ff_buf++ = *src_u8++; - } - - // Read more bytes to beginning to complete a word - ff_buf = f->buffer; - while (remrem--) { - *ff_buf++ = *src_u8++; - } + ff_buf = f->buffer + remrem; // wrap around } else { ff_buf = f->buffer; // wrap around to beginning } // Write data wrapped part if (wrap_bytes > 0) { - _ff_push_const_addr(ff_buf, app_buf, wrap_bytes); + ff_push_fixed_addr_rw32(ff_buf, reg_rx, wrap_bytes); } } break; + } #endif default: @@ -226,13 +187,8 @@ static void _ff_push_n(tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t w } } -// get one item from fifo WITHOUT updating read pointer -static inline void _ff_pull(tu_fifo_t *f, void *app_buf, uint16_t rel) { - memcpy(app_buf, f->buffer + (rel * f->item_size), f->item_size); -} - // get n items from fifo WITHOUT updating read pointer -static void _ff_pull_n(tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr, tu_fifo_copy_mode_t copy_mode) { +static void ff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr, tu_fifo_access_mode_t copy_mode) { const uint16_t lin_count = f->depth - rd_ptr; const uint16_t wrap_count = n - lin_count; // only used if wrapped @@ -240,70 +196,56 @@ static void _ff_pull_n(tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr, uint16_t wrap_bytes = wrap_count * f->item_size; // current buffer of fifo - uint8_t *ff_buf = f->buffer + (rd_ptr * f->item_size); + const uint8_t *ff_buf = f->buffer + (rd_ptr * f->item_size); switch (copy_mode) { - case TU_FIFO_COPY_INC: + case TU_FIFO_INC_ADDR_RW8: if (n <= lin_count) { // Linear only memcpy(app_buf, ff_buf, n * f->item_size); } else { // Wrap around - - // Read data from linear part of buffer - memcpy(app_buf, ff_buf, lin_bytes); - - // Read data wrapped part - memcpy((uint8_t *)app_buf + lin_bytes, f->buffer, wrap_bytes); + memcpy(app_buf, ff_buf, lin_bytes); // linear part + memcpy((uint8_t *)app_buf + lin_bytes, f->buffer, wrap_bytes); // wrapped part } break; -#ifdef TUP_MEM_CONST_ADDR - case TU_FIFO_COPY_CST_FULL_WORDS: +#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32 + case TU_FIFO_FIXED_ADDR_RW32: { + volatile uint32_t *reg_tx = (volatile uint32_t *)app_buf; + if (n <= lin_count) { // Linear only - _ff_pull_const_addr(app_buf, ff_buf, n * f->item_size); + ff_pull_fixed_addr_rw32(reg_tx, ff_buf, n * f->item_size); } else { // Wrap around case - // Read full words from linear part of buffer + // Read full words from linear part uint16_t lin_4n_bytes = lin_bytes & 0xFFFC; - _ff_pull_const_addr(app_buf, ff_buf, lin_4n_bytes); + ff_pull_fixed_addr_rw32(reg_tx, ff_buf, lin_4n_bytes); ff_buf += lin_4n_bytes; // There could be odd 1-3 bytes before the wrap-around boundary - uint8_t rem = lin_bytes & 0x03; + const uint8_t rem = lin_bytes & 0x03; if (rem > 0) { - volatile uint32_t *reg_tx = (volatile uint32_t *)app_buf; + const uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem); + const uint32_t scatter32 = tu_scatter_read32(ff_buf, rem, f->buffer, remrem); - uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem); - wrap_bytes -= remrem; + *reg_tx = scatter32; - uint32_t tmp32 = 0; - uint8_t *dst_u8 = (uint8_t *)&tmp32; - - // Read 1-3 bytes before wrapped boundary - while (rem--) { - *dst_u8++ = *ff_buf++; - } - - // Read more bytes from beginning to complete a word - ff_buf = f->buffer; - while (remrem--) { - *dst_u8++ = *ff_buf++; - } - - *reg_tx = tmp32; + wrap_bytes -= remrem; + ff_buf = f->buffer + remrem; // wrap around } else { - ff_buf = f->buffer; // wrap around to beginning + ff_buf = f->buffer; // wrap around to beginning } // Read data wrapped part if (wrap_bytes > 0) { - _ff_pull_const_addr(app_buf, ff_buf, wrap_bytes); + ff_pull_fixed_addr_rw32(reg_tx, ff_buf, wrap_bytes); } } break; + } #endif default: @@ -312,32 +254,12 @@ static void _ff_pull_n(tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr, } //--------------------------------------------------------------------+ -// Helper -//--------------------------------------------------------------------+ - -// return only the index difference and as such can be used to determine an overflow i.e overflowable count -TU_ATTR_ALWAYS_INLINE static inline uint16_t _ff_count(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) { - // In case we have non-power of two depth we need a further modification - if (wr_idx >= rd_idx) { - return (uint16_t)(wr_idx - rd_idx); - } else { - return (uint16_t)(2 * depth - (rd_idx - wr_idx)); - } -} - -// return remaining slot in fifo -TU_ATTR_ALWAYS_INLINE static inline uint16_t _ff_remaining(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx) { - const uint16_t count = _ff_count(depth, wr_idx, rd_idx); - return (depth > count) ? (depth - count) : 0; -} - -//--------------------------------------------------------------------+ // Index Helper //--------------------------------------------------------------------+ // Advance an absolute index // "absolute" index is only in the range of [0..2*depth) -static uint16_t advance_index(uint16_t depth, uint16_t idx, uint16_t offset) { +TU_ATTR_ALWAYS_INLINE static inline uint16_t advance_index(uint16_t depth, uint16_t idx, 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 @@ -350,23 +272,7 @@ static uint16_t advance_index(uint16_t depth, uint16_t idx, uint16_t offset) { return new_idx; } -#if 0 // not used but -// Backward an absolute index -static uint16_t backward_index(uint16_t depth, uint16_t idx, 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 - uint16_t new_idx = (uint16_t) (idx - offset); - if ( (idx < new_idx) || (new_idx >= 2*depth) ) { - uint16_t const non_used_index_space = (uint16_t) (UINT16_MAX - (2*depth-1)); - new_idx = (uint16_t) (new_idx - non_used_index_space); - } - - return new_idx; -} -#endif - -// index to pointer, simply an modulo with minus. +// index to pointer (0..depth-1), simply a modulo with minus. TU_ATTR_ALWAYS_INLINE static inline uint16_t idx2ptr(uint16_t depth, uint16_t idx) { // Only run at most 3 times since index is limit in the range of [0..2*depth) while (idx >= depth) { @@ -376,9 +282,8 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t idx2ptr(uint16_t depth, uint16_t id } // Works on local copies of w -// When an overwritable fifo is overflowed, rd_idx will be re-index so that it forms -// an full fifo i.e _ff_count() = depth -TU_ATTR_ALWAYS_INLINE static inline uint16_t _ff_correct_read_index(tu_fifo_t *f, uint16_t wr_idx) { +// When an overwritable fifo is overflowed, rd_idx will be re-index so that it forms a full fifo +TU_ATTR_ALWAYS_INLINE static inline uint16_t correct_read_index(tu_fifo_t *f, uint16_t wr_idx) { uint16_t rd_idx; if (wr_idx >= f->depth) { rd_idx = wr_idx - f->depth; @@ -387,91 +292,87 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t _ff_correct_read_index(tu_fifo_t *f } f->rd_idx = rd_idx; - return rd_idx; } -// 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(tu_fifo_t *f, void *p_buffer, uint16_t wr_idx, uint16_t rd_idx) { - uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); - - // nothing to peek - if (cnt == 0) { - return false; +// peek() using local write/read index. Be careful, caller must not lock mutex, since this Will also try to lock mutex +// in case of overflowed to correct read index +static bool ff_peek_local(tu_fifo_t *f, void *buf, uint16_t wr_idx, uint16_t rd_idx) { + const uint16_t ovf_count = tu_ff_overflow_count(f->depth, wr_idx, rd_idx); + if (ovf_count == 0) { + return false; // nothing to peek } - // Check overflow and correct if required - if (cnt > f->depth) { - rd_idx = _ff_correct_read_index(f, wr_idx); + // Correct read index if overflow + if (ovf_count > f->depth) { + ff_lock(f->mutex_rd); + rd_idx = correct_read_index(f, wr_idx); + ff_unlock(f->mutex_rd); } - uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); - - // Peek data - _ff_pull(f, p_buffer, rd_ptr); + const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); + memcpy(buf, f->buffer + (rd_ptr * f->item_size), f->item_size); return true; } +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + // 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_n( - tu_fifo_t *f, void *p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx, tu_fifo_copy_mode_t copy_mode) { - uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); +uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx, + tu_fifo_access_mode_t access_mode) { + uint16_t ovf_cnt = tu_ff_overflow_count(f->depth, wr_idx, rd_idx); - // nothing to peek - if (cnt == 0) { - return 0; + if (ovf_cnt == 0) { + return 0; // nothing to peek } // Check overflow and correct if required - if (cnt > f->depth) { - rd_idx = _ff_correct_read_index(f, wr_idx); - cnt = f->depth; + if (ovf_cnt > f->depth) { + rd_idx = correct_read_index(f, wr_idx); + ovf_cnt = f->depth; } - // Check if we can read something at and after offset - if too less is available we read what remains - if (cnt < n) { - n = cnt; + if (ovf_cnt < n) { + n = ovf_cnt; // limit to available count } - uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); - - // Peek data - _ff_pull_n(f, p_buffer, n, rd_ptr, copy_mode); + const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); + ff_pull_n(f, p_buffer, n, rd_ptr, access_mode); return n; } -static uint16_t _tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n, tu_fifo_copy_mode_t copy_mode) { +uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n, tu_fifo_access_mode_t access_mode) { if (n == 0) { return 0; } - _ff_lock(f->mutex_wr); + ff_lock(f->mutex_wr); uint16_t wr_idx = f->wr_idx; uint16_t rd_idx = f->rd_idx; const uint8_t *buf8 = (const uint8_t *)data; - TU_LOG( - TU_FIFO_DBG, "rd = %3u, wr = %3u, count = %3u, remain = %3u, n = %3u: ", rd_idx, wr_idx, - _ff_count(f->depth, wr_idx, rd_idx), _ff_remaining(f->depth, wr_idx, rd_idx), n); + TU_LOG(TU_FIFO_DBG, "rd = %3u, wr = %3u, count = %3u, remain = %3u, n = %3u: ", rd_idx, wr_idx, + tu_ff_overflow_count(f->depth, wr_idx, rd_idx), tu_ff_remaining_local(f->depth, wr_idx, rd_idx), n); if (!f->overwritable) { // limit up to full - const uint16_t remain = _ff_remaining(f->depth, wr_idx, rd_idx); + const uint16_t remain = tu_ff_remaining_local(f->depth, wr_idx, rd_idx); n = tu_min16(n, remain); } else { // In over-writable mode, fifo_write() is allowed even when fifo is full. In such case, - // oldest data in fifo i.e at read pointer data will be overwritten - // Note: we can modify read buffer contents but we must not modify the read index itself within a write function! - // Since it would end up in a race condition with read functions! + // oldest data in fifo i.e. at read pointer data will be overwritten + // Note: we can modify read buffer contents however we must not modify the read index itself within a write + // function! Since it would end up in a race condition with read functions! if (n >= f->depth) { // Only copy last part - if (copy_mode == TU_FIFO_COPY_INC) { + if (access_mode == TU_FIFO_INC_ADDR_RW8) { buf8 += (n - f->depth) * f->item_size; } else { // TODO should read from hw fifo to discard data, however reading an odd number could @@ -483,7 +384,7 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n, tu_ // We start writing at the read pointer's position since we fill the whole buffer wr_idx = rd_idx; } else { - const uint16_t overflowable_count = _ff_count(f->depth, wr_idx, rd_idx); + const uint16_t overflowable_count = tu_ff_overflow_count(f->depth, wr_idx, rd_idx); if (overflowable_count + n >= 2 * f->depth) { // Double overflowed // Index is bigger than the allowed range [0,2*depth) @@ -504,121 +405,36 @@ static uint16_t _tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n, tu_ } if (n) { - uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); + const uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); TU_LOG(TU_FIFO_DBG, "actual_n = %u, wr_ptr = %u", n, wr_ptr); - _ff_push_n(f, buf8, n, wr_ptr, copy_mode); + ff_push_n(f, buf8, n, wr_ptr, access_mode); f->wr_idx = advance_index(f->depth, wr_idx, n); TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\r\n", f->wr_idx); } - _ff_unlock(f->mutex_wr); + ff_unlock(f->mutex_wr); return n; } -static uint16_t _tu_fifo_read_n(tu_fifo_t *f, void *buffer, uint16_t n, tu_fifo_copy_mode_t copy_mode) { - _ff_lock(f->mutex_rd); +uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, tu_fifo_access_mode_t access_mode) { + ff_lock(f->mutex_rd); - // Peek the data - // 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 + // Peek the data: f->rd_idx might get modified in case of an overflow so we can not use a local variable + n = tu_fifo_peek_n_access_mode(f, buffer, n, f->wr_idx, f->rd_idx, access_mode); f->rd_idx = advance_index(f->depth, f->rd_idx, n); - _ff_unlock(f->mutex_rd); + ff_unlock(f->mutex_rd); return n; } -//--------------------------------------------------------------------+ -// Application API -//--------------------------------------------------------------------+ - -/******************************************************************************/ -/*! - @brief Get number of items in FIFO. - - As this function only reads the read and write pointers once, this function is - reentrant and thus thread and ISR save without any mutexes. In case an - overflow occurred, this function return f.depth at maximum. Overflows are - checked and corrected for in the read functions! - - @param[in] f - Pointer to the FIFO buffer to manipulate - - @returns Number of items in FIFO - */ -/******************************************************************************/ -uint16_t tu_fifo_count(const tu_fifo_t *f) { - return tu_min16(_ff_count(f->depth, f->wr_idx, f->rd_idx), f->depth); -} - -/******************************************************************************/ -/*! - @brief Check if FIFO is full. - - As this function only reads the read and write pointers once, this function is - reentrant and thus thread and ISR save without any mutexes. - - @param[in] f - Pointer to the FIFO buffer to manipulate - - @returns Number of items in FIFO - */ -/******************************************************************************/ -bool tu_fifo_full(const tu_fifo_t *f) { - return _ff_count(f->depth, f->wr_idx, f->rd_idx) >= f->depth; -} - -/******************************************************************************/ -/*! - @brief Get remaining space in FIFO. - - As this function only reads the read and write pointers once, this function is - reentrant and thus thread and ISR save without any mutexes. - - @param[in] f - Pointer to the FIFO buffer to manipulate - - @returns Number of items in FIFO - */ -/******************************************************************************/ -uint16_t tu_fifo_remaining(const tu_fifo_t *f) { - return _ff_remaining(f->depth, f->wr_idx, f->rd_idx); -} - -/******************************************************************************/ -/*! - @brief Check if overflow happened. - - BE AWARE - THIS FUNCTION MIGHT NOT GIVE A CORRECT ANSWERE IN CASE WRITE POINTER "OVERFLOWS" - Only one overflow is allowed for this function to work e.g. if depth = 100, you must not - write more than 2*depth-1 items in one rush without updating write pointer. Otherwise - write pointer wraps and your pointer states are messed up. This can only happen if you - use DMAs, write functions do not allow such an error. Avoid such nasty things! - - All reading functions (read, peek) check for overflows and correct read pointer on their own such - that latest items are read. - If required (e.g. for DMA use) you can also correct the read pointer by - tu_fifo_correct_read_pointer(). - - @param[in] f - Pointer to the FIFO buffer to manipulate - - @returns True if overflow happened - */ -/******************************************************************************/ -bool tu_fifo_overflowed(const tu_fifo_t *f) { - return _ff_count(f->depth, f->wr_idx, f->rd_idx) > f->depth; -} - // Only use in case tu_fifo_overflow() returned true! void tu_fifo_correct_read_pointer(tu_fifo_t *f) { - _ff_lock(f->mutex_rd); - _ff_correct_read_index(f, f->wr_idx); - _ff_unlock(f->mutex_rd); + ff_lock(f->mutex_rd); + correct_read_index(f, f->wr_idx); + ff_unlock(f->mutex_rd); } /******************************************************************************/ @@ -638,64 +454,20 @@ void tu_fifo_correct_read_pointer(tu_fifo_t *f) { */ /******************************************************************************/ bool tu_fifo_read(tu_fifo_t *f, void *buffer) { - _ff_lock(f->mutex_rd); - // Peek the data // 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_index(f->depth, f->rd_idx, ret); + const bool ret = ff_peek_local(f, buffer, f->wr_idx, f->rd_idx); + if (ret) { + ff_lock(f->mutex_rd); + f->rd_idx = advance_index(f->depth, f->rd_idx, 1); + ff_unlock(f->mutex_rd); + } - _ff_unlock(f->mutex_rd); return ret; } /******************************************************************************/ /*! - @brief This function will read n elements from the array index specified by - the read pointer and increment the read index. - This function checks for an overflow and corrects read pointer if required. - - @param[in] f - Pointer to the FIFO buffer to manipulate - @param[in] buffer - The pointer to data location - @param[in] n - Number of element that buffer can afford - - @returns number of items read from the FIFO - */ -/******************************************************************************/ -uint16_t tu_fifo_read_n(tu_fifo_t *f, void *buffer, uint16_t n) { - return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_INC); -} - -#ifdef TUP_MEM_CONST_ADDR -/******************************************************************************/ -/*! - @brief This function will read n elements from the array index specified by - the read pointer and increment the read index. - This function checks for an overflow and corrects read pointer if required. - The dest address will not be incremented which is useful for writing to registers. - - @param[in] f - Pointer to the FIFO buffer to manipulate - @param[in] buffer - The pointer to data location - @param[in] n - Number of element that buffer can afford - - @returns number of items read from the FIFO - */ -/******************************************************************************/ -uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t *f, void *buffer, uint16_t n) { - return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_CST_FULL_WORDS); -} -#endif - -/******************************************************************************/ -/*! @brief Read one item without removing it from the FIFO. This function checks for an overflow and corrects read pointer if required. @@ -708,10 +480,7 @@ uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t *f, void *buffer, uint16 */ /******************************************************************************/ bool tu_fifo_peek(tu_fifo_t *f, void *p_buffer) { - _ff_lock(f->mutex_rd); - bool ret = _tu_fifo_peek(f, p_buffer, f->wr_idx, f->rd_idx); - _ff_unlock(f->mutex_rd); - return ret; + return ff_peek_local(f, p_buffer, f->wr_idx, f->rd_idx); } /******************************************************************************/ @@ -730,9 +499,9 @@ bool tu_fifo_peek(tu_fifo_t *f, void *p_buffer) { */ /******************************************************************************/ uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n) { - _ff_lock(f->mutex_rd); - uint16_t ret = _tu_fifo_peek_n(f, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_COPY_INC); - _ff_unlock(f->mutex_rd); + ff_lock(f->mutex_rd); + const uint16_t ret = tu_fifo_peek_n_access_mode(f, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_INC_ADDR_RW8); + ff_unlock(f->mutex_rd); return ret; } @@ -753,66 +522,27 @@ uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n) { */ /******************************************************************************/ bool tu_fifo_write(tu_fifo_t *f, const void *data) { - _ff_lock(f->mutex_wr); + bool ret; + ff_lock(f->mutex_wr); - bool ret; const uint16_t wr_idx = f->wr_idx; if (tu_fifo_full(f) && !f->overwritable) { ret = false; } else { - uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); - _ff_push(f, data, wr_ptr); + const uint16_t wr_ptr = idx2ptr(f->depth, wr_idx); + memcpy(f->buffer + (wr_ptr * f->item_size), data, f->item_size); f->wr_idx = advance_index(f->depth, wr_idx, 1); ret = true; } - _ff_unlock(f->mutex_wr); + ff_unlock(f->mutex_wr); return ret; } /******************************************************************************/ /*! - @brief This function will write n elements into the array index specified by - the write pointer and increment the write index. - - @param[in] f - Pointer to the FIFO buffer to manipulate - @param[in] data - The pointer to data to add to the FIFO - @param[in] count - Number of element - @return Number of written elements - */ -/******************************************************************************/ -uint16_t tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n) { - return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_INC); -} - -#ifdef TUP_MEM_CONST_ADDR -/******************************************************************************/ -/*! - @brief This function will write n elements into the array index specified by - the write pointer and increment the write index. The source address will - not be incremented which is useful for reading from registers. - - @param[in] f - Pointer to the FIFO buffer to manipulate - @param[in] data - The pointer to data to add to the FIFO - @param[in] count - Number of element - @return Number of written elements - */ -/******************************************************************************/ -uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t *f, const void *data, uint16_t n) { - return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_CST_FULL_WORDS); -} -#endif - -/******************************************************************************/ -/*! @brief Clear the fifo read and write pointers @param[in] f @@ -820,14 +550,14 @@ uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t *f, const void *data, u */ /******************************************************************************/ bool tu_fifo_clear(tu_fifo_t *f) { - _ff_lock(f->mutex_wr); - _ff_lock(f->mutex_rd); + ff_lock(f->mutex_wr); + ff_lock(f->mutex_rd); f->rd_idx = 0; f->wr_idx = 0; - _ff_unlock(f->mutex_wr); - _ff_unlock(f->mutex_rd); + ff_unlock(f->mutex_wr); + ff_unlock(f->mutex_rd); return true; } @@ -846,13 +576,13 @@ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) { return true; } - _ff_lock(f->mutex_wr); - _ff_lock(f->mutex_rd); + ff_lock(f->mutex_wr); + ff_lock(f->mutex_rd); f->overwritable = overwritable; - _ff_unlock(f->mutex_wr); - _ff_unlock(f->mutex_rd); + ff_unlock(f->mutex_wr); + ff_unlock(f->mutex_rd); return true; } @@ -917,23 +647,23 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { uint16_t wr_idx = f->wr_idx; uint16_t rd_idx = f->rd_idx; - uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx); + uint16_t cnt = tu_ff_overflow_count(f->depth, wr_idx, rd_idx); // Check overflow and correct if required - may happen in case a DMA wrote too fast if (cnt > f->depth) { - _ff_lock(f->mutex_rd); - rd_idx = _ff_correct_read_index(f, wr_idx); - _ff_unlock(f->mutex_rd); + ff_lock(f->mutex_rd); + rd_idx = correct_read_index(f, wr_idx); + ff_unlock(f->mutex_rd); cnt = f->depth; } // Check if fifo is empty if (cnt == 0) { - info->len_lin = 0; - info->len_wrap = 0; - info->ptr_lin = NULL; - info->ptr_wrap = NULL; + info->linear.len = 0; + info->wrapped.len = 0; + info->linear.ptr = NULL; + info->wrapped.ptr = NULL; return; } @@ -942,20 +672,20 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); // Copy pointer to buffer to start reading from - info->ptr_lin = &f->buffer[rd_ptr]; + info->linear.ptr = &f->buffer[rd_ptr]; // Check if there is a wrap around necessary if (wr_ptr > rd_ptr) { // Non wrapping case - info->len_lin = cnt; + info->linear.len = cnt; - info->len_wrap = 0; - info->ptr_wrap = NULL; + info->wrapped.len = 0; + info->wrapped.ptr = NULL; } else { - info->len_lin = f->depth - rd_ptr; // Also the case if FIFO was full + info->linear.len = f->depth - rd_ptr; // Also the case if FIFO was full - info->len_wrap = cnt - info->len_lin; - info->ptr_wrap = f->buffer; + info->wrapped.len = cnt - info->linear.len; + info->wrapped.ptr = f->buffer; } } @@ -977,13 +707,13 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { uint16_t wr_idx = f->wr_idx; uint16_t rd_idx = f->rd_idx; - uint16_t remain = _ff_remaining(f->depth, wr_idx, rd_idx); + uint16_t remain = tu_ff_remaining_local(f->depth, wr_idx, rd_idx); if (remain == 0) { - info->len_lin = 0; - info->len_wrap = 0; - info->ptr_lin = NULL; - info->ptr_wrap = NULL; + info->linear.len = 0; + info->wrapped.len = 0; + info->linear.ptr = NULL; + info->wrapped.ptr = NULL; return; } @@ -992,16 +722,16 @@ void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) { uint16_t rd_ptr = idx2ptr(f->depth, rd_idx); // Copy pointer to buffer to start writing to - info->ptr_lin = &f->buffer[wr_ptr]; + info->linear.ptr = &f->buffer[wr_ptr]; if (wr_ptr < rd_ptr) { // Non wrapping case - info->len_lin = rd_ptr - wr_ptr; - info->len_wrap = 0; - info->ptr_wrap = NULL; + info->linear.len = rd_ptr - wr_ptr; + info->wrapped.len = 0; + info->wrapped.ptr = NULL; } else { - info->len_lin = f->depth - wr_ptr; - info->len_wrap = remain - info->len_lin; // Remaining length - n already was limited to remain or FIFO depth - info->ptr_wrap = f->buffer; // Always start of buffer + info->linear.len = f->depth - wr_ptr; + info->wrapped.len = remain - info->linear.len; // Remaining length - n already was limited to remain or FIFO depth + info->wrapped.ptr = f->buffer; // Always start of buffer } } |
