Merge pull request #804 from hathach/audio_make_dma_ready

Implement functions to allow for DMA usage in audio driver.
This commit is contained in:
Ha Thach 2021-05-02 15:29:38 +07:00 committed by GitHub
commit 42a1d2f3b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 372 additions and 215 deletions

View File

@ -11,6 +11,9 @@
- Rename tud_midi_receive() to tud_midi_packet_read()
- Rename tud_midi_send() to tud_midi_packet_write()
- New board stm32f072-eval
- Breaking changes
- tud_cdc_peek(), tud_vendor_peek() dropped position parameter. If needed, tu_fifo_get_read_info() can be used to peek
at random offset.
## 0.9.0 - 2021.03.12

View File

@ -55,9 +55,9 @@
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
#include "audio_device.h"
#include "class/audio/audio.h"
#include "device/usbd_pvt.h"
#include "audio_device.h"
//#include "common/tusb_fifo.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
@ -447,27 +447,39 @@ bool tud_audio_n_clear_ep_out_ff(uint8_t func_id)
return tu_fifo_clear(&_audiod_fct[func_id].ep_out_ff);
}
tu_fifo_t* tud_audio_n_get_ep_out_ff(uint8_t func_id)
{
if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_out_ff;
return NULL;
}
#endif
#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
// Delete all content in the support RX FIFOs
bool tud_audio_n_clear_rx_support_ff(uint8_t func_id, uint8_t ff_idx)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL, ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
return tu_fifo_clear(&_audiod_fct[func_id].rx_supp_ff[ff_idx]);
}
uint16_t tud_audio_n_available_support_ff(uint8_t func_id, uint8_t ff_idx)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL, ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
return tu_fifo_count(&_audiod_fct[func_id].rx_supp_ff[ff_idx]);
}
uint16_t tud_audio_n_read_support_ff(uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL, ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
return tu_fifo_read_n(&_audiod_fct[func_id].rx_supp_ff[ff_idx], buffer, bufsize);
}
tu_fifo_t* tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx)
{
if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff) return &_audiod_fct[func_id].rx_supp_ff[ff_idx];
return NULL;
}
#endif
// This function is called once an audio packet is received by the USB and is responsible for putting data from USB memory into EP_OUT_FIFO (or support FIFOs + decoding of received stream into audio channels).
@ -635,31 +647,30 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, u
uint8_t cnt_ff;
// Decode
void * dst;
uint8_t * src;
uint8_t * dst_end;
uint16_t len;
tu_fifo_buffer_info_t info;
for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++)
{
src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx];
tu_fifo_get_write_info(&audio->rx_supp_ff[cnt_ff], &info);
len = tu_fifo_get_linear_write_info(&audio->rx_supp_ff[cnt_ff], 0, &dst, nBytesPerFFToRead);
tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], len);
dst_end = dst + len;
src = audiod_interleaved_copy_bytes_fast_decode(nBytesToCopy, dst, dst_end, src, n_ff_used);
// Handle wrapped part of FIFO
if (len < nBytesPerFFToRead)
if (info.len_lin != 0)
{
len = tu_fifo_get_linear_write_info(&audio->rx_supp_ff[cnt_ff], 0, &dst, nBytesPerFFToRead - len);
tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], len);
info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin);
src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx];
dst_end = info.ptr_lin + info.len_lin;
src = audiod_interleaved_copy_bytes_fast_decode(nBytesToCopy, info.ptr_lin, dst_end, src, n_ff_used);
dst_end = dst + len;
audiod_interleaved_copy_bytes_fast_decode(nBytesToCopy, dst, dst_end, src, n_ff_used);
// Handle wrapped part of FIFO
info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap);
if (info.len_wrap != 0)
{
dst_end = info.ptr_wrap + info.len_wrap;
audiod_interleaved_copy_bytes_fast_decode(nBytesToCopy, info.ptr_wrap, dst_end, src, n_ff_used);
}
tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
}
}
@ -699,9 +710,16 @@ bool tud_audio_n_clear_ep_in_ff(uint8_t func_id) // Del
return tu_fifo_clear(&_audiod_fct[func_id].ep_in_ff);
}
tu_fifo_t* tud_audio_n_get_ep_in_ff(uint8_t func_id)
{
if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_in_ff;
return NULL;
}
#endif
#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
uint16_t tud_audio_n_flush_tx_support_ff(uint8_t func_id) // Force all content in the support TX FIFOs to be written into linear buffer and schedule a transmit
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
@ -719,15 +737,22 @@ uint16_t tud_audio_n_flush_tx_support_ff(uint8_t func_id) // For
bool tud_audio_n_clear_tx_support_ff(uint8_t func_id, uint8_t ff_idx)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL, ff_idx < _audiod_fct[func_id].n_tx_supp_ff);
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff);
return tu_fifo_clear(&_audiod_fct[func_id].tx_supp_ff[ff_idx]);
}
uint16_t tud_audio_n_write_support_ff(uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL, ff_idx < _audiod_fct[func_id].n_tx_supp_ff);
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff);
return tu_fifo_write_n(&_audiod_fct[func_id].tx_supp_ff[ff_idx], data, len);
}
tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx)
{
if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff) return &_audiod_fct[func_id].tx_supp_ff[ff_idx];
return NULL;
}
#endif
@ -751,6 +776,7 @@ uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint1
return true;
}
#endif
@ -952,31 +978,34 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
nBytesPerFFToSend = (nBytesPerFFToSend / nBytesToCopy) * nBytesToCopy;
// Encode
void * src;
uint8_t * dst;
uint8_t * src_end;
uint16_t len;
tu_fifo_buffer_info_t info;
for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++)
{
dst = &audio->lin_buf_in[cnt_ff*audio->n_channels_per_ff_tx*audio->n_bytes_per_sampe_tx];
len = tu_fifo_get_linear_read_info(&audio->tx_supp_ff[cnt_ff], 0, &src, nBytesPerFFToSend);
tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], len);
tu_fifo_get_read_info(&audio->tx_supp_ff[cnt_ff], &info);
src_end = src + len;
dst = audiod_interleaved_copy_bytes_fast_encode(nBytesToCopy, src, src_end, dst, n_ff_used);
// Handle wrapped part of FIFO
if (len < nBytesPerFFToSend)
if (info.len_lin != 0)
{
len = tu_fifo_get_linear_read_info(&audio->tx_supp_ff[cnt_ff], 0, &src, nBytesPerFFToSend - len);
tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], len);
info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin); // Limit up to desired length
src_end = info.ptr_lin + info.len_lin;
dst = audiod_interleaved_copy_bytes_fast_encode(nBytesToCopy, info.ptr_lin, src_end, dst, n_ff_used);
src_end = src + len;
// Limit up to desired length
info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap);
audiod_interleaved_copy_bytes_fast_encode(nBytesToCopy, src, src_end, dst, n_ff_used);
// Handle wrapped part of FIFO
if (info.len_wrap != 0)
{
src_end = info.ptr_wrap + info.len_wrap;
audiod_interleaved_copy_bytes_fast_encode(nBytesToCopy, info.ptr_wrap, src_end, dst, n_ff_used);
}
tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
}
}

View File

@ -364,23 +364,27 @@ bool tud_audio_n_mounted (uint8_t func_id);
uint16_t tud_audio_n_available (uint8_t func_id);
uint16_t tud_audio_n_read (uint8_t func_id, void* buffer, uint16_t bufsize);
bool tud_audio_n_clear_ep_out_ff (uint8_t func_id); // Delete all content in the EP OUT FIFO
tu_fifo_t* tud_audio_n_get_ep_out_ff (uint8_t func_id);
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
bool tud_audio_n_clear_rx_support_ff (uint8_t func_id, uint8_t ff_idx); // Delete all content in the support RX FIFOs
uint16_t tud_audio_n_available_support_ff (uint8_t func_id, uint8_t ff_idx);
uint16_t tud_audio_n_read_support_ff (uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize);
tu_fifo_t* tud_audio_n_get_rx_support_ff (uint8_t func_id, uint8_t ff_idx);
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
uint16_t tud_audio_n_write (uint8_t func_id, const void * data, uint16_t len);
bool tud_audio_n_clear_ep_in_ff (uint8_t func_id); // Delete all content in the EP IN FIFO
tu_fifo_t* tud_audio_n_get_ep_in_ff (uint8_t func_id);
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
uint16_t tud_audio_n_flush_tx_support_ff (uint8_t func_id); // Force all content in the support TX FIFOs to be written into EP SW FIFO
bool tud_audio_n_clear_tx_support_ff (uint8_t func_id, uint8_t ff_idx);
uint16_t tud_audio_n_write_support_ff (uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len);
tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_idx);
#endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
@ -399,12 +403,14 @@ static inline bool tud_audio_mounted (void);
static inline uint16_t tud_audio_available (void);
static inline bool tud_audio_clear_ep_out_ff (void); // Delete all content in the EP OUT FIFO
static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize);
static inline tu_fifo_t* tud_audio_get_ep_out_ff (void);
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
static inline bool tud_audio_clear_rx_support_ff (uint8_t ff_idx);
static inline uint16_t tud_audio_available_support_ff (uint8_t ff_idx);
static inline uint16_t tud_audio_read_support_ff (uint8_t ff_idx, void* buffer, uint16_t bufsize);
static inline tu_fifo_t* tud_audio_get_rx_support_ff (uint8_t ff_idx);
#endif
// TX API
@ -412,12 +418,14 @@ static inline uint16_t tud_audio_read_support_ff (uint8_t ff_idx, voi
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
static inline uint16_t tud_audio_write (const void * data, uint16_t len);
static inline bool tud_audio_clear_ep_in_ff (void);
static inline tu_fifo_t* tud_audio_get_ep_in_ff (void);
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
static inline uint16_t tud_audio_flush_tx_support_ff (void);
static inline uint16_t tud_audio_clear_tx_support_ff (uint8_t ff_idx);
static inline uint16_t tud_audio_write_support_ff (uint8_t ff_idx, const void * data, uint16_t len);
static inline tu_fifo_t* tud_audio_get_tx_support_ff (uint8_t ff_idx);
#endif
// INT CTR API
@ -514,6 +522,11 @@ static inline bool tud_audio_clear_ep_out_ff(void)
return tud_audio_n_clear_ep_out_ff(0);
}
static inline tu_fifo_t* tud_audio_get_ep_out_ff(void)
{
return tud_audio_n_get_ep_out_ff(0);
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
@ -533,6 +546,11 @@ static inline uint16_t tud_audio_read_support_ff(uint8_t ff_idx, void* buffer, u
return tud_audio_n_read_support_ff(0, ff_idx, buffer, bufsize);
}
static inline tu_fifo_t* tud_audio_get_rx_support_ff(uint8_t ff_idx)
{
return tud_audio_n_get_rx_support_ff(0, ff_idx);
}
#endif
// TX API
@ -549,6 +567,11 @@ static inline bool tud_audio_clear_ep_in_ff(void)
return tud_audio_n_clear_ep_in_ff(0);
}
static inline tu_fifo_t* tud_audio_get_ep_in_ff(void)
{
return tud_audio_n_get_ep_in_ff(0);
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
@ -568,6 +591,11 @@ static inline uint16_t tud_audio_write_support_ff(uint8_t ff_idx, const void * d
return tud_audio_n_write_support_ff(0, ff_idx, data, len);
}
static inline tu_fifo_t* tud_audio_get_tx_support_ff(uint8_t ff_idx)
{
return tud_audio_n_get_tx_support_ff(0, ff_idx);
}
#endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN

View File

@ -146,9 +146,9 @@ uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize)
return num_read;
}
bool tud_cdc_n_peek(uint8_t itf, int pos, uint8_t* chr)
bool tud_cdc_n_peek(uint8_t itf, uint8_t* chr)
{
return tu_fifo_peek_at(&_cdcd_itf[itf].rx_ff, pos, chr);
return tu_fifo_peek(&_cdcd_itf[itf].rx_ff, chr);
}
void tud_cdc_n_read_flush (uint8_t itf)

View File

@ -83,7 +83,7 @@ int32_t tud_cdc_n_read_char (uint8_t itf);
void tud_cdc_n_read_flush (uint8_t itf);
// Get a byte from FIFO at the specified position without removing it
bool tud_cdc_n_peek (uint8_t itf, int pos, uint8_t* u8);
bool tud_cdc_n_peek (uint8_t itf, uint8_t* u8);
// Write bytes to TX FIFO, data may remain in the FIFO for a while
uint32_t tud_cdc_n_write (uint8_t itf, void const* buffer, uint32_t bufsize);
@ -117,7 +117,7 @@ static inline uint32_t tud_cdc_available (void);
static inline int32_t tud_cdc_read_char (void);
static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize);
static inline void tud_cdc_read_flush (void);
static inline bool tud_cdc_peek (int pos, uint8_t* u8);
static inline bool tud_cdc_peek (uint8_t* u8);
static inline uint32_t tud_cdc_write_char (char ch);
static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize);
@ -207,9 +207,9 @@ static inline void tud_cdc_read_flush (void)
tud_cdc_n_read_flush(0);
}
static inline bool tud_cdc_peek (int pos, uint8_t* u8)
static inline bool tud_cdc_peek (uint8_t* u8)
{
return tud_cdc_n_peek(0, pos, u8);
return tud_cdc_n_peek(0, u8);
}
static inline uint32_t tud_cdc_write_char (char ch)

View File

@ -72,9 +72,9 @@ uint32_t tud_vendor_n_available (uint8_t itf)
return tu_fifo_count(&_vendord_itf[itf].rx_ff);
}
bool tud_vendor_n_peek(uint8_t itf, int pos, uint8_t* u8)
bool tud_vendor_n_peek(uint8_t itf, uint8_t* u8)
{
return tu_fifo_peek_at(&_vendord_itf[itf].rx_ff, pos, u8);
return tu_fifo_peek(&_vendord_itf[itf].rx_ff, u8);
}
//--------------------------------------------------------------------+

View File

@ -45,7 +45,7 @@ bool tud_vendor_n_mounted (uint8_t itf);
uint32_t tud_vendor_n_available (uint8_t itf);
uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize);
bool tud_vendor_n_peek (uint8_t itf, int pos, uint8_t* u8);
bool tud_vendor_n_peek (uint8_t itf, uint8_t* u8);
uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize);
uint32_t tud_vendor_n_write_available (uint8_t itf);
@ -59,7 +59,7 @@ uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str);
static inline bool tud_vendor_mounted (void);
static inline uint32_t tud_vendor_available (void);
static inline uint32_t tud_vendor_read (void* buffer, uint32_t bufsize);
static inline bool tud_vendor_peek (int pos, uint8_t* u8);
static inline bool tud_vendor_peek (uint8_t* u8);
static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize);
static inline uint32_t tud_vendor_write_str (char const* str);
static inline uint32_t tud_vendor_write_available (void);
@ -95,9 +95,9 @@ static inline uint32_t tud_vendor_read (void* buffer, uint32_t bufsize)
return tud_vendor_n_read(0, buffer, bufsize);
}
static inline bool tud_vendor_peek (int pos, uint8_t* u8)
static inline bool tud_vendor_peek (uint8_t* u8)
{
return tud_vendor_n_peek(0, pos, u8);
return tud_vendor_n_peek(0, u8);
}
static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize)

View File

@ -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);
// Copy pointer to buffer to start reading from
info->ptr_lin = &f->buffer[r];
// Check if there is a wrap around necessary
uint16_t len;
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);
info->len_lin = 0;
info->len_wrap = 0;
info->ptr_lin = NULL;
info->ptr_wrap = NULL;
return;
}
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;
}
// 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;
}

View File

@ -25,10 +25,6 @@
* This file is part of the TinyUSB stack.
*/
/** \ingroup Group_Common
* \defgroup group_fifo fifo
* @{ */
#ifndef _TUSB_FIFO_H_
#define _TUSB_FIFO_H_
@ -62,16 +58,16 @@ extern "C" {
*/
typedef struct
{
uint8_t* buffer ; ///< buffer pointer
uint16_t depth ; ///< max items
uint16_t item_size ; ///< size of each item
bool overwritable ;
uint8_t* buffer ; ///< buffer pointer
uint16_t depth ; ///< max items
uint16_t item_size ; ///< size of each item
bool overwritable ;
uint16_t non_used_index_space ; ///< required for non-power-of-two buffer length
uint16_t max_pointer_idx ; ///< maximum absolute pointer index
uint16_t non_used_index_space ; ///< required for non-power-of-two buffer length
uint16_t max_pointer_idx ; ///< maximum absolute pointer index
volatile uint16_t wr_idx ; ///< write pointer
volatile uint16_t rd_idx ; ///< read pointer
volatile uint16_t wr_idx ; ///< write pointer
volatile uint16_t rd_idx ; ///< read pointer
#if CFG_FIFO_MUTEX
tu_fifo_mutex_t mutex_wr;
@ -80,6 +76,14 @@ typedef struct
} tu_fifo_t;
typedef struct
{
uint16_t len_lin ; ///< linear length in item size
uint16_t len_wrap ; ///< wrapped length in item size
void * ptr_lin ; ///< linear part start pointer
void * ptr_wrap ; ///< wrapped part start pointer
} tu_fifo_buffer_info_t;
#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable) \
{ \
.buffer = _buffer, \
@ -115,8 +119,8 @@ bool tu_fifo_read (tu_fifo_t* f, void * p_buffer);
uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t n);
uint16_t tu_fifo_read_n_const_addr_full_words (tu_fifo_t* f, void * buffer, uint16_t n);
bool tu_fifo_peek_at (tu_fifo_t* f, uint16_t pos, void * p_buffer);
uint16_t tu_fifo_peek_at_n (tu_fifo_t* f, uint16_t pos, void * p_buffer, uint16_t n);
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);
uint16_t tu_fifo_count (tu_fifo_t* f);
bool tu_fifo_empty (tu_fifo_t* f);
@ -125,27 +129,22 @@ uint16_t tu_fifo_remaining (tu_fifo_t* f);
bool tu_fifo_overflowed (tu_fifo_t* f);
void tu_fifo_correct_read_pointer (tu_fifo_t* f);
static inline uint16_t tu_fifo_depth(tu_fifo_t* f)
{
return f->depth;
}
// Pointer modifications intended to be used in combinations with DMAs.
// USE WITH CARE - NO SAFTY CHECKS CONDUCTED HERE! NOT MUTEX PROTECTED!
void tu_fifo_advance_write_pointer (tu_fifo_t *f, uint16_t n);
void tu_fifo_advance_read_pointer (tu_fifo_t *f, uint16_t n);
// If you want to read/write from/to the FIFO by use of a DMA, you may need to conduct two copies to handle a possible wrapping part
// This functions deliver a pointer to start reading/writing from/to and a valid linear length along which no wrap occurs.
// In case not all of your data is available within one read/write, update the read/write pointer by
// tu_fifo_advance_read_pointer()/tu_fifo_advance_write_pointer and conduct a second read/write operation
uint16_t tu_fifo_get_linear_read_info (tu_fifo_t *f, uint16_t offset, void **ptr, uint16_t n);
uint16_t tu_fifo_get_linear_write_info (tu_fifo_t *f, uint16_t offset, void **ptr, uint16_t n);
// If you want to read/write from/to the FIFO by use of a DMA, you may need to conduct two copies
// to handle a possible wrapping part. These functions deliver a pointer to start
// reading/writing from/to and a valid linear length along which no wrap occurs.
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);
static inline bool tu_fifo_peek(tu_fifo_t* f, void * p_buffer)
{
return tu_fifo_peek_at(f, 0, p_buffer);
}
static inline uint16_t tu_fifo_depth(tu_fifo_t* f)
{
return f->depth;
}
#ifdef __cplusplus
}

View File

@ -993,7 +993,7 @@ static bool dcd_write_packet_memory_ff(tu_fifo_t * ff, uint16_t dst, uint16_t wN
// Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies
// Check for first linear part
void * src;
uint16_t len = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes); // We want to read from the FIFO
uint16_t len = tu_fifo_get_linear_read_info(ff, 0, &src, wNBytes); // We want to read from the FIFO - THIS FUNCTION CHANGED!!!
TU_VERIFY(len && dcd_write_packet_memory(dst, src, len)); // and write it into the PMA
tu_fifo_advance_read_pointer(ff, len);
@ -1075,7 +1075,7 @@ static bool dcd_read_packet_memory_ff(tu_fifo_t * ff, uint16_t src, uint16_t wNB
// Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies
// Check for first linear part
void * dst;
uint16_t len = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes);
uint16_t len = tu_fifo_get_linear_write_info(ff, 0, &dst, wNBytes); // THIS FUNCTION CHANGED!!!!
TU_VERIFY(len && dcd_read_packet_memory(dst, src, len));
tu_fifo_advance_write_pointer(ff, len);

View File

@ -24,15 +24,19 @@
* This file is part of the TinyUSB stack.
*/
#include <string.h>
#include "unity.h"
#include "tusb_fifo.h"
#define FIFO_SIZE 10
TU_FIFO_DEF(ff, FIFO_SIZE, uint8_t, false);
TU_FIFO_DEF(tu_ff, FIFO_SIZE, uint8_t, false);
tu_fifo_t* ff = &tu_ff;
tu_fifo_buffer_info_t info;
void setUp(void)
{
tu_fifo_clear(&ff);
tu_fifo_clear(ff);
memset(&info, 0, sizeof(tu_fifo_buffer_info_t));
}
void tearDown(void)
@ -44,12 +48,12 @@ void tearDown(void)
//--------------------------------------------------------------------+
void test_normal(void)
{
for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(&ff, &i);
for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(ff, &i);
for(uint8_t i=0; i < FIFO_SIZE; i++)
{
uint8_t c;
tu_fifo_read(&ff, &c);
tu_fifo_read(ff, &c);
TEST_ASSERT_EQUAL(i, c);
}
}
@ -86,30 +90,30 @@ void test_read_n(void)
uint8_t data[20];
for(int i=0; i<sizeof(data); i++) data[i] = i;
for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(&ff, data+i);
for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(ff, data+i);
uint8_t rd[10];
uint16_t rd_count;
// case 1: Read index + count < depth
// read 0 -> 4
rd_count = tu_fifo_read_n(&ff, rd, 5);
rd_count = tu_fifo_read_n(ff, rd, 5);
TEST_ASSERT_EQUAL( 5, rd_count );
TEST_ASSERT_EQUAL_MEMORY( data, rd, rd_count ); // 0 -> 4
// case 2: Read index + count > depth
// write 10, 11, 12
tu_fifo_write(&ff, data+10);
tu_fifo_write(&ff, data+11);
tu_fifo_write(&ff, data+12);
tu_fifo_write(ff, data+10);
tu_fifo_write(ff, data+11);
tu_fifo_write(ff, data+12);
rd_count = tu_fifo_read_n(&ff, rd, 7);
rd_count = tu_fifo_read_n(ff, rd, 7);
TEST_ASSERT_EQUAL( 7, rd_count );
TEST_ASSERT_EQUAL_MEMORY( data+5, rd, rd_count ); // 5 -> 11
// Should only read until empty
TEST_ASSERT_EQUAL( 1, tu_fifo_read_n(&ff, rd, 100) );
TEST_ASSERT_EQUAL( 1, tu_fifo_read_n(ff, rd, 100) );
}
void test_write_n(void)
@ -119,55 +123,172 @@ void test_write_n(void)
for(int i=0; i<sizeof(data); i++) data[i] = i;
// case 1: wr + count < depth
tu_fifo_write_n(&ff, data, 8); // wr = 8, count = 8
tu_fifo_write_n(ff, data, 8); // wr = 8, count = 8
uint8_t rd[10];
uint16_t rd_count;
rd_count = tu_fifo_read_n(&ff, rd, 5); // wr = 8, count = 3
rd_count = tu_fifo_read_n(ff, rd, 5); // wr = 8, count = 3
TEST_ASSERT_EQUAL( 5, rd_count );
TEST_ASSERT_EQUAL_MEMORY( data, rd, rd_count ); // 0 -> 4
// case 2: wr + count > depth
tu_fifo_write_n(&ff, data+8, 6); // wr = 3, count = 9
tu_fifo_write_n(ff, data+8, 6); // wr = 3, count = 9
for(rd_count=0; rd_count<7; rd_count++) tu_fifo_read(&ff, rd+rd_count); // wr = 3, count = 2
for(rd_count=0; rd_count<7; rd_count++) tu_fifo_read(ff, rd+rd_count); // wr = 3, count = 2
TEST_ASSERT_EQUAL_MEMORY( data+5, rd, rd_count); // 5 -> 11
TEST_ASSERT_EQUAL(2, tu_fifo_count(&ff));
TEST_ASSERT_EQUAL(2, tu_fifo_count(ff));
}
void test_peek(void)
{
uint8_t temp;
temp = 10; tu_fifo_write(&ff, &temp);
temp = 20; tu_fifo_write(&ff, &temp);
temp = 30; tu_fifo_write(&ff, &temp);
temp = 10; tu_fifo_write(ff, &temp);
temp = 20; tu_fifo_write(ff, &temp);
temp = 30; tu_fifo_write(ff, &temp);
temp = 0;
tu_fifo_peek(&ff, &temp);
tu_fifo_peek(ff, &temp);
TEST_ASSERT_EQUAL(10, temp);
tu_fifo_peek_at(&ff, 1, &temp);
TEST_ASSERT_EQUAL(20, temp);
tu_fifo_read(ff, &temp);
tu_fifo_read(ff, &temp);
tu_fifo_peek(ff, &temp);
TEST_ASSERT_EQUAL(30, temp);
}
void test_get_read_info_when_no_wrap()
{
uint8_t ch = 1;
// write 6 items
for(uint8_t i=0; i < 6; i++) tu_fifo_write(ff, &ch);
// read 2 items
tu_fifo_read(ff, &ch);
tu_fifo_read(ff, &ch);
tu_fifo_get_read_info(ff, &info);
TEST_ASSERT_EQUAL(4, info.len_lin);
TEST_ASSERT_EQUAL(0, info.len_wrap);
TEST_ASSERT_EQUAL_PTR(ff->buffer+2, info.ptr_lin);
TEST_ASSERT_NULL(info.ptr_wrap);
}
void test_get_read_info_when_wrapped()
{
uint8_t ch = 1;
// make fifo full
for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(ff, &ch);
// read 6 items
for(uint8_t i=0; i < 6; i++) tu_fifo_read(ff, &ch);
// write 2 items
tu_fifo_write(ff, &ch);
tu_fifo_write(ff, &ch);
tu_fifo_get_read_info(ff, &info);
TEST_ASSERT_EQUAL(FIFO_SIZE-6, info.len_lin);
TEST_ASSERT_EQUAL(2, info.len_wrap);
TEST_ASSERT_EQUAL_PTR(ff->buffer+6, info.ptr_lin);
TEST_ASSERT_EQUAL_PTR(ff->buffer, info.ptr_wrap);
}
void test_get_write_info_when_no_wrap()
{
uint8_t ch = 1;
// write 2 items
tu_fifo_write(ff, &ch);
tu_fifo_write(ff, &ch);
tu_fifo_get_write_info(ff, &info);
TEST_ASSERT_EQUAL(FIFO_SIZE-2, info.len_lin);
TEST_ASSERT_EQUAL(0, info.len_wrap);
TEST_ASSERT_EQUAL_PTR(ff->buffer+2, info .ptr_lin);
// application should check len instead of ptr.
// TEST_ASSERT_NULL(info.ptr_wrap);
}
void test_get_write_info_when_wrapped()
{
uint8_t ch = 1;
// write 6 items
for(uint8_t i=0; i < 6; i++) tu_fifo_write(ff, &ch);
// read 2 items
tu_fifo_read(ff, &ch);
tu_fifo_read(ff, &ch);
tu_fifo_get_write_info(ff, &info);
TEST_ASSERT_EQUAL(FIFO_SIZE-6, info.len_lin);
TEST_ASSERT_EQUAL(2, info.len_wrap);
TEST_ASSERT_EQUAL_PTR(ff->buffer+6, info .ptr_lin);
TEST_ASSERT_EQUAL_PTR(ff->buffer, info.ptr_wrap);
}
void test_empty(void)
{
uint8_t temp;
TEST_ASSERT_TRUE(tu_fifo_empty(&ff));
tu_fifo_write(&ff, &temp);
TEST_ASSERT_FALSE(tu_fifo_empty(&ff));
TEST_ASSERT_TRUE(tu_fifo_empty(ff));
// read info
tu_fifo_get_read_info(ff, &info);
TEST_ASSERT_EQUAL(0, info.len_lin);
TEST_ASSERT_EQUAL(0, info.len_wrap);
TEST_ASSERT_NULL(info.ptr_lin);
TEST_ASSERT_NULL(info.ptr_wrap);
// write info
tu_fifo_get_write_info(ff, &info);
TEST_ASSERT_EQUAL(FIFO_SIZE, info.len_lin);
TEST_ASSERT_EQUAL(0, info.len_wrap);
TEST_ASSERT_EQUAL_PTR(ff->buffer, info .ptr_lin);
// application should check len instead of ptr.
// TEST_ASSERT_NULL(info.ptr_wrap);
// write 1 then re-check empty
tu_fifo_write(ff, &temp);
TEST_ASSERT_FALSE(tu_fifo_empty(ff));
}
void test_full(void)
{
TEST_ASSERT_FALSE(tu_fifo_full(&ff));
TEST_ASSERT_FALSE(tu_fifo_full(ff));
for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(&ff, &i);
for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(ff, &i);
TEST_ASSERT_TRUE(tu_fifo_full(&ff));
TEST_ASSERT_TRUE(tu_fifo_full(ff));
// read info
tu_fifo_get_read_info(ff, &info);
TEST_ASSERT_EQUAL(FIFO_SIZE, info.len_lin);
TEST_ASSERT_EQUAL(0, info.len_wrap);
TEST_ASSERT_EQUAL_PTR(ff->buffer, info.ptr_lin);
// skip this, application must check len instead of buffer
// TEST_ASSERT_NULL(info.ptr_wrap);
// write info
}