mirror of
https://github.com/hathach/tinyusb.git
synced 2025-01-17 05:32:55 +08:00
Improve tu_fifo capabilites
Added tu_fifo_get_linear_write_info(), tu_fifo_backward_write_pointer(), and tu_fifo_backward_read_pointer()
This commit is contained in:
parent
a5d7b6266d
commit
c87357c025
@ -354,10 +354,7 @@ static uint16_t _tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffe
|
||||
|
||||
// Check if we can read something at and after offset - if too less is available we read what remains
|
||||
cnt -= offset;
|
||||
if (cnt < n) {
|
||||
if (cnt == 0) return 0;
|
||||
n = cnt;
|
||||
}
|
||||
if (cnt < n) n = cnt;
|
||||
|
||||
uint16_t rRel = get_relative_pointer(f, rAbs, offset);
|
||||
|
||||
@ -664,10 +661,7 @@ uint16_t tu_fifo_peek_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint
|
||||
|
||||
// Check if we can read something at and after offset - if too less is available we read what remains
|
||||
cnt -= offset;
|
||||
if (cnt < n) {
|
||||
if (cnt == 0) return 0;
|
||||
n = cnt;
|
||||
}
|
||||
if (cnt < n) n = cnt;
|
||||
|
||||
tu_fifo_lock(f_target); // Lock both read and write pointers - in case of an overwritable FIFO both may be modified
|
||||
|
||||
@ -881,3 +875,195 @@ void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n)
|
||||
{
|
||||
f->rd_idx = advance_pointer(f, f->rd_idx, n);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief Move back write pointer - intended to be used in combination with DMA.
|
||||
It is possible to fill the FIFO by use of a DMA in circular mode. Within
|
||||
DMA ISRs you may update the write pointer to be able to read from the FIFO.
|
||||
As long as the DMA is the only process writing into the FIFO this is safe
|
||||
to use.
|
||||
|
||||
USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE!
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
@param[in] n
|
||||
Number of items the write pointer moves backward
|
||||
*/
|
||||
/******************************************************************************/
|
||||
void tu_fifo_backward_write_pointer(tu_fifo_t *f, uint16_t n)
|
||||
{
|
||||
f->wr_idx = backward_pointer(f, f->wr_idx, n);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief Move back read pointer - intended to be used in combination with DMA.
|
||||
It is possible to read from the FIFO by use of a DMA in linear mode. Within
|
||||
DMA ISRs you may update the read pointer to be able to again write into the
|
||||
FIFO. As long as the DMA is the only process reading from the FIFO this is
|
||||
safe to use.
|
||||
|
||||
USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE!
|
||||
|
||||
@param[in] f
|
||||
Pointer to the FIFO buffer to manipulate
|
||||
@param[in] n
|
||||
Number of items the read pointer moves backward
|
||||
*/
|
||||
/******************************************************************************/
|
||||
void tu_fifo_backward_read_pointer(tu_fifo_t *f, uint16_t n)
|
||||
{
|
||||
f->rd_idx = backward_pointer(f, f->rd_idx, n);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*!
|
||||
@brief Get linear 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 BYTES 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!
|
||||
@param[in] f
|
||||
Pointer to FIFO
|
||||
@param[in] offset
|
||||
Number of BYTES to ignore before start writing
|
||||
@param[out] **ptr
|
||||
Pointer to start writing to
|
||||
@param[in] n
|
||||
Number of BYTES to read from buffer
|
||||
@return len
|
||||
Length of linear part IN BYTES, if zero corresponding pointer ptr is invalid
|
||||
*/
|
||||
/******************************************************************************/
|
||||
uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr, uint16_t n)
|
||||
{
|
||||
// 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
|
||||
if (cnt > f->depth)
|
||||
{
|
||||
tu_fifo_lock(f);
|
||||
_tu_fifo_correct_read_pointer(f, w);
|
||||
tu_fifo_unlock(f);
|
||||
r = f->rd_idx;
|
||||
cnt = f->depth;
|
||||
}
|
||||
|
||||
// Convert to bytes
|
||||
cnt = cnt * f->item_size;
|
||||
|
||||
// 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;
|
||||
|
||||
// Get relative pointers
|
||||
w = get_relative_pointer(f, w, 0);
|
||||
r = get_relative_pointer(f, r, offset);
|
||||
|
||||
// Check if there is a wrap around necessary
|
||||
uint16_t len;
|
||||
|
||||
if (w >= r) {
|
||||
len = w - r;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = f->depth - r;
|
||||
}
|
||||
|
||||
len = len * f->item_size;
|
||||
|
||||
// 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!
|
||||
@param[in] f
|
||||
Pointer to FIFO
|
||||
@param[in] offset
|
||||
Number of bytes to ignore before start writing
|
||||
@param[out] **ptr
|
||||
Pointer to start writing to
|
||||
@param[in] n
|
||||
Number of BYTES to write into buffer
|
||||
@return len
|
||||
Length of linear part IN BYTES, if zero corresponding pointer ptr is invalid
|
||||
*/
|
||||
/******************************************************************************/
|
||||
uint16_t tu_fifo_get_linear_write_info(tu_fifo_t *f, uint16_t offset, void **ptr, uint16_t n)
|
||||
{
|
||||
uint16_t w = f->wr_idx, r = f->rd_idx;
|
||||
uint16_t free = _tu_fifo_remaining(f, w, r) * f->item_size;
|
||||
|
||||
if (!f->overwritable)
|
||||
{
|
||||
// Not overwritable limit up to full
|
||||
n = tu_min16(n, free);
|
||||
}
|
||||
else if (n >= f->depth * f->item_size)
|
||||
{
|
||||
// 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 * f->item_size);
|
||||
|
||||
n = f->depth * f->item_size;
|
||||
// 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;
|
||||
|
||||
if (w < r)
|
||||
{
|
||||
len = r-w;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = f->depth - w;
|
||||
}
|
||||
|
||||
len = len * f->item_size;
|
||||
|
||||
// Limit to required length
|
||||
len = tu_min16(n, len);
|
||||
|
||||
// Copy pointer to buffer to start reading from
|
||||
*ptr = &f->buffer[w];
|
||||
|
||||
return len;
|
||||
}
|
||||
|
@ -134,7 +134,16 @@ void tu_fifo_correct_read_pointer (tu_fifo_t* f);
|
||||
// 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_backward_write_pointer (tu_fifo_t *f, uint16_t n);
|
||||
void tu_fifo_advance_read_pointer (tu_fifo_t *f, uint16_t n);
|
||||
void tu_fifo_backward_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);
|
||||
|
||||
static inline bool tu_fifo_peek(tu_fifo_t* f, void * p_buffer)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user