Implement audio PCM type I enc./decoding acc. to 2.3.1.5 Audio Streams
Extending capabilities of support FIFOs Removing copy from to FIFO Adjusting audio examples Remove peek/read into other FIFO
This commit is contained in:
parent
de1f36f2b0
commit
d5a5a1cab6
|
@ -73,12 +73,12 @@ int main(void)
|
||||||
tusb_init();
|
tusb_init();
|
||||||
|
|
||||||
// Init values
|
// Init values
|
||||||
sampFreq = 48000;
|
sampFreq = AUDIO_SAMPLE_RATE;
|
||||||
clkValid = 1;
|
clkValid = 1;
|
||||||
|
|
||||||
sampleFreqRng.wNumSubRanges = 1;
|
sampleFreqRng.wNumSubRanges = 1;
|
||||||
sampleFreqRng.subrange[0].bMin = 48000;
|
sampleFreqRng.subrange[0].bMin = AUDIO_SAMPLE_RATE;
|
||||||
sampleFreqRng.subrange[0].bMax = 48000;
|
sampleFreqRng.subrange[0].bMax = AUDIO_SAMPLE_RATE;
|
||||||
sampleFreqRng.subrange[0].bRes = 0;
|
sampleFreqRng.subrange[0].bRes = 0;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
|
|
|
@ -91,9 +91,12 @@ extern "C" {
|
||||||
// AUDIO CLASS DRIVER CONFIGURATION
|
// AUDIO CLASS DRIVER CONFIGURATION
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef AUDIO_SAMPLE_RATE
|
||||||
|
#define AUDIO_SAMPLE_RATE 48000
|
||||||
|
#endif
|
||||||
|
|
||||||
// Audio format type
|
// Audio format type
|
||||||
#define CFG_TUD_AUDIO_FORMAT_TYPE_TX AUDIO_FORMAT_TYPE_I
|
#define CFG_TUD_AUDIO_FORMAT_TYPE_TX AUDIO_FORMAT_TYPE_I
|
||||||
#define CFG_TUD_AUDIO_FORMAT_TYPE_RX AUDIO_FORMAT_TYPE_UNDEFINED
|
|
||||||
|
|
||||||
// Audio format type I specifications
|
// Audio format type I specifications
|
||||||
#define CFG_TUD_AUDIO_FORMAT_TYPE_I_TX AUDIO_DATA_FORMAT_TYPE_I_PCM
|
#define CFG_TUD_AUDIO_FORMAT_TYPE_I_TX AUDIO_DATA_FORMAT_TYPE_I_PCM
|
||||||
|
@ -101,8 +104,8 @@ extern "C" {
|
||||||
#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 2
|
#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 2
|
||||||
|
|
||||||
// EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense)
|
// EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense)
|
||||||
#define CFG_TUD_AUDIO_EPSIZE_IN 48*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX*CFG_TUD_AUDIO_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x 1 Channels
|
#define CFG_TUD_AUDIO_EPSIZE_IN 48 * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_N_CHANNELS_TX // ceil(f_s/1000) * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_N_CHANNELS_TX
|
||||||
#define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_IN + 1 // Just for safety one sample more space
|
#define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_IN + CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_N_CHANNELS_TX // Just for safety one sample more space
|
||||||
|
|
||||||
// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
|
// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
|
||||||
#define CFG_TUD_AUDIO_N_AS_INT 1
|
#define CFG_TUD_AUDIO_N_AS_INT 1
|
||||||
|
|
|
@ -110,7 +110,6 @@ extern "C" {
|
||||||
#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 2
|
#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 2
|
||||||
#define CFG_TUD_AUDIO_N_CHANNELS_RX 2
|
#define CFG_TUD_AUDIO_N_CHANNELS_RX 2
|
||||||
#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX 2
|
#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX 2
|
||||||
#define CFG_TUD_AUDIO_RX_ITEMSIZE 2
|
|
||||||
#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0
|
#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0
|
||||||
|
|
||||||
// EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense)
|
// EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense)
|
||||||
|
|
|
@ -161,18 +161,18 @@ typedef struct
|
||||||
|
|
||||||
// Support FIFOs
|
// Support FIFOs
|
||||||
#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
|
#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
|
||||||
tu_fifo_t tx_supp_ff[CFG_TUD_AUDIO_N_CHANNELS_TX];
|
tu_fifo_t tx_supp_ff[CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO];
|
||||||
CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_TX][CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE];
|
CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf[CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO][CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX];
|
||||||
#if CFG_FIFO_MUTEX
|
#if CFG_FIFO_MUTEX
|
||||||
osal_mutex_def_t tx_supp_ff_mutex_wr[CFG_TUD_AUDIO_N_CHANNELS_TX]; // No need for read mutex as only USB driver reads from FIFO
|
osal_mutex_def_t tx_supp_ff_mutex_wr[CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
|
#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
|
||||||
tu_fifo_t rx_supp_ff[CFG_TUD_AUDIO_N_CHANNELS_RX];
|
tu_fifo_t rx_supp_ff[CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO];
|
||||||
CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_RX][CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE];
|
CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf[CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO][CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX];
|
||||||
#if CFG_FIFO_MUTEX
|
#if CFG_FIFO_MUTEX
|
||||||
osal_mutex_def_t rx_supp_ff_mutex_rd[CFG_TUD_AUDIO_N_CHANNELS_RX]; // No need for write mutex as only USB driver writes into FIFO
|
osal_mutex_def_t rx_supp_ff_mutex_rd[CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -284,19 +284,19 @@ bool tud_audio_n_clear_ep_out_ff(uint8_t itf)
|
||||||
// Delete all content in the support RX FIFOs
|
// Delete all content in the support RX FIFOs
|
||||||
bool tud_audio_n_clear_rx_support_ff(uint8_t itf, uint8_t channelId)
|
bool tud_audio_n_clear_rx_support_ff(uint8_t itf, uint8_t channelId)
|
||||||
{
|
{
|
||||||
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX);
|
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO);
|
||||||
return tu_fifo_clear(&_audiod_itf[itf].rx_supp_ff[channelId]);
|
return tu_fifo_clear(&_audiod_itf[itf].rx_supp_ff[channelId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t tud_audio_n_available_support_ff(uint8_t itf, uint8_t channelId)
|
uint16_t tud_audio_n_available_support_ff(uint8_t itf, uint8_t channelId)
|
||||||
{
|
{
|
||||||
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX);
|
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO);
|
||||||
return tu_fifo_count(&_audiod_itf[itf].rx_supp_ff[channelId]);
|
return tu_fifo_count(&_audiod_itf[itf].rx_supp_ff[channelId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t tud_audio_n_read_support_ff(uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize)
|
uint16_t tud_audio_n_read_support_ff(uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize)
|
||||||
{
|
{
|
||||||
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX);
|
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO);
|
||||||
return tu_fifo_read_n(&_audiod_itf[itf].rx_supp_ff[channelId], buffer, bufsize);
|
return tu_fifo_read_n(&_audiod_itf[itf].rx_supp_ff[channelId], buffer, bufsize);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -382,35 +382,55 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_
|
||||||
|
|
||||||
// The following functions are used in case CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE != 0
|
// The following functions are used in case CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE != 0
|
||||||
#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT
|
#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_OUT
|
||||||
|
|
||||||
|
// Decoding according to 2.3.1.5 Audio Streams
|
||||||
static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio, uint16_t n_bytes_received)
|
static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio, uint16_t n_bytes_received)
|
||||||
{
|
{
|
||||||
(void) rhport;
|
(void) rhport;
|
||||||
|
|
||||||
// We assume there is always the correct number of samples available for decoding - extra checks make no sense here
|
// Determine amount of samples
|
||||||
|
uint16_t const nChannelsPerFF = CFG_TUD_AUDIO_N_CHANNELS_RX / CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO;
|
||||||
|
uint16_t const nBytesToCopy = nChannelsPerFF*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX;
|
||||||
|
uint16_t const nSamplesPerFFToRead = n_bytes_received / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX / CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO;
|
||||||
|
uint8_t cnt_ff;
|
||||||
|
|
||||||
uint16_t cnt = CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX;
|
// Decode
|
||||||
uint16_t idxSample = 0;
|
void * dst;
|
||||||
|
uint8_t * src;
|
||||||
|
uint8_t * dst_end;
|
||||||
|
uint16_t len;
|
||||||
|
|
||||||
while (cnt <= n_bytes_received)
|
for (cnt_ff = 0; cnt_ff < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; cnt_ff++)
|
||||||
{
|
{
|
||||||
for (uint8_t cntChannel = 0; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_RX; cntChannel++)
|
src = &audio->lin_buf_out[cnt_ff*nChannelsPerFF*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX];
|
||||||
{
|
|
||||||
// If 8, 16, or 32 bit values are to be copied
|
|
||||||
#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX == CFG_TUD_AUDIO_RX_ITEMSIZE
|
|
||||||
// If this aborts then the target buffer is full
|
|
||||||
TU_VERIFY(tu_fifo_write_n(&audio->rx_supp_ff[cntChannel], &audio->lin_buf_out[idxSample], CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX));
|
|
||||||
#else
|
|
||||||
uint32_t sample = audio->lin_buf_out[idxSample];
|
|
||||||
#if CFG_TUD_AUDIO_JUSTIFICATION_RX == CFG_TUD_AUDIO_LEFT_JUSTIFIED
|
|
||||||
sample = sample << 8;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TU_VERIFY(tu_fifo_write_n(&audio->rx_supp_ff[cntChannel], &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX));
|
len = tu_fifo_get_linear_write_info(&audio->rx_supp_ff[cnt_ff], 0, &dst, nSamplesPerFFToRead);
|
||||||
#endif
|
tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], len);
|
||||||
idxSample += CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX;
|
|
||||||
|
dst_end = dst + len * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX;
|
||||||
|
|
||||||
|
while((uint8_t *)dst < dst_end)
|
||||||
|
{
|
||||||
|
memcpy(dst, src, nBytesToCopy);
|
||||||
|
dst = (uint8_t *)dst + nBytesToCopy;
|
||||||
|
src += nBytesToCopy * CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO;
|
||||||
}
|
}
|
||||||
|
|
||||||
cnt += CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX;
|
// Handle wrapped part of FIFO
|
||||||
|
if (len < nSamplesPerFFToRead)
|
||||||
|
{
|
||||||
|
len = tu_fifo_get_linear_write_info(&audio->rx_supp_ff[cnt_ff], 0, &dst, nSamplesPerFFToRead - len);
|
||||||
|
tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], len);
|
||||||
|
|
||||||
|
dst_end = dst + len * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX;
|
||||||
|
|
||||||
|
while((uint8_t *)dst < dst_end)
|
||||||
|
{
|
||||||
|
memcpy(dst, src, nBytesToCopy);
|
||||||
|
dst = (uint8_t *)dst + nBytesToCopy;
|
||||||
|
src += nBytesToCopy * CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it
|
// Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it
|
||||||
|
@ -469,13 +489,13 @@ uint16_t tud_audio_n_flush_tx_support_ff(uint8_t itf) // Force a
|
||||||
|
|
||||||
bool tud_audio_n_clear_tx_support_ff(uint8_t itf, uint8_t channelId)
|
bool tud_audio_n_clear_tx_support_ff(uint8_t itf, uint8_t channelId)
|
||||||
{
|
{
|
||||||
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_TX);
|
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO);
|
||||||
return tu_fifo_clear(&_audiod_itf[itf].tx_supp_ff[channelId]);
|
return tu_fifo_clear(&_audiod_itf[itf].tx_supp_ff[channelId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t tud_audio_n_write_support_ff(uint8_t itf, uint8_t channelId, const void * data, uint16_t len)
|
uint16_t tud_audio_n_write_support_ff(uint8_t itf, uint8_t channelId, const void * data, uint16_t len)
|
||||||
{
|
{
|
||||||
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_TX);
|
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO);
|
||||||
return tu_fifo_write_n(&_audiod_itf[itf].tx_supp_ff[channelId], data, len);
|
return tu_fifo_write_n(&_audiod_itf[itf].tx_supp_ff[channelId], data, len);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -590,60 +610,91 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio)
|
||||||
#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN
|
#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE && CFG_TUD_AUDIO_EPSIZE_IN
|
||||||
// Take samples from the support buffer and encode them into the IN EP software FIFO
|
// Take samples from the support buffer and encode them into the IN EP software FIFO
|
||||||
// Returns number of bytes written into linear buffer
|
// Returns number of bytes written into linear buffer
|
||||||
|
|
||||||
|
/* 2.3.1.7.1 PCM Format
|
||||||
|
The PCM (Pulse Coded Modulation) format is the most commonly used audio format to represent audio
|
||||||
|
data streams. The audio data is not compressed and uses a signed two’s-complement fixed point format. It
|
||||||
|
is left-justified (the sign bit is the Msb) and data is padded with trailing zeros to fill the remaining unused
|
||||||
|
bits of the subslot. The binary point is located to the right of the sign bit so that all values lie within the
|
||||||
|
range [-1, +1)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function encodes channels saved within the support FIFOs into one stream by interleaving the PCM samples
|
||||||
|
* in the support FIFOs according to 2.3.1.5 Audio Streams. It does not control justification (left or right) and
|
||||||
|
* does not change the number of bytes per sample.
|
||||||
|
* */
|
||||||
|
|
||||||
static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio)
|
static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_interface_t* audio)
|
||||||
{
|
{
|
||||||
// We encode directly into IN EP's FIFO - abort if previous transfer not complete
|
// We encode directly into IN EP's linear buffer - abort if previous transfer not complete
|
||||||
TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in));
|
TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in));
|
||||||
|
|
||||||
// Determine amount of samples
|
// Determine amount of samples
|
||||||
uint16_t const nEndpointSampleCapacity = CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE / CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX;
|
uint16_t const nChannelsPerFF = CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO;
|
||||||
uint16_t nSamplesPerChannelToSend = tu_fifo_count(&audio->tx_supp_ff[0]); // We first look for the minimum number of bytes and afterwards convert it to sample size
|
uint16_t const nBytesToCopy = nChannelsPerFF*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX;
|
||||||
uint8_t cntChannel;
|
uint16_t const capSamplesPerFF = CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX / CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO;
|
||||||
|
uint16_t nSamplesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]);
|
||||||
|
uint8_t cnt_ff;
|
||||||
|
|
||||||
for (cntChannel = 1; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_TX; cntChannel++)
|
for (cnt_ff = 1; cnt_ff < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; cnt_ff++)
|
||||||
{
|
{
|
||||||
uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cntChannel]);
|
uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cnt_ff]);
|
||||||
if (count < nSamplesPerChannelToSend)
|
if (count < nSamplesPerFFToSend)
|
||||||
{
|
{
|
||||||
nSamplesPerChannelToSend = count;
|
nSamplesPerFFToSend = count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to sample size
|
|
||||||
nSamplesPerChannelToSend = nSamplesPerChannelToSend / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX;
|
|
||||||
|
|
||||||
// Check if there is enough
|
// Check if there is enough
|
||||||
if (nSamplesPerChannelToSend == 0) return 0;
|
if (nSamplesPerFFToSend == 0) return 0;
|
||||||
|
|
||||||
// Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT!
|
// Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT!
|
||||||
nSamplesPerChannelToSend = tu_min16(nSamplesPerChannelToSend, nEndpointSampleCapacity);
|
nSamplesPerFFToSend = tu_min16(nSamplesPerFFToSend, capSamplesPerFF);
|
||||||
|
|
||||||
|
// Round to full number of samples (flooring)
|
||||||
|
nSamplesPerFFToSend = (nSamplesPerFFToSend / nChannelsPerFF) * nChannelsPerFF;
|
||||||
|
|
||||||
// Encode
|
// Encode
|
||||||
uint16_t cntSample;
|
void * src;
|
||||||
uint16_t idxSample = 0;
|
uint8_t * dst;
|
||||||
|
uint8_t * src_end;
|
||||||
|
uint16_t len;
|
||||||
|
|
||||||
for (cntSample = 0; cntSample < nSamplesPerChannelToSend; cntSample++)
|
for (cnt_ff = 0; cnt_ff < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; cnt_ff++)
|
||||||
{
|
{
|
||||||
for (cntChannel = 0; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_TX; cntChannel++)
|
dst = &audio->lin_buf_in[cnt_ff*nChannelsPerFF*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX];
|
||||||
|
|
||||||
|
len = tu_fifo_get_linear_read_info(&audio->tx_supp_ff[cnt_ff], 0, &src, nSamplesPerFFToSend);
|
||||||
|
tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], len);
|
||||||
|
|
||||||
|
src_end = src + len * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX;
|
||||||
|
|
||||||
|
while((uint8_t *)src < src_end)
|
||||||
{
|
{
|
||||||
// If 8, 16, or 32 bit values are to be copied
|
memcpy(dst, src, nBytesToCopy);
|
||||||
#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == CFG_TUD_AUDIO_TX_ITEMSIZE
|
src = (uint8_t *)src + nBytesToCopy;
|
||||||
tu_fifo_read_n(&audio->tx_supp_ff[cntChannel], &audio->lin_buf_in[idxSample], CFG_TUD_AUDIO_TX_ITEMSIZE);
|
dst += nBytesToCopy * CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO;
|
||||||
#else
|
}
|
||||||
uint32_t sample = 0;
|
|
||||||
|
|
||||||
// Get sample from buffer
|
// Handle wrapped part of FIFO
|
||||||
tu_fifo_read_n(&audio->tx_supp_ff[cntChannel], &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX);
|
if (len < nSamplesPerFFToSend)
|
||||||
|
{
|
||||||
|
len = tu_fifo_get_linear_read_info(&audio->tx_supp_ff[cnt_ff], 0, &src, nSamplesPerFFToSend - len);
|
||||||
|
tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], len);
|
||||||
|
|
||||||
#if CFG_TUD_AUDIO_JUSTIFICATION_TX == CFG_TUD_AUDIO_LEFT_JUSTIFIED
|
src_end = src + len * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX;
|
||||||
sample = sample << 8;
|
|
||||||
#endif
|
while((uint8_t *)src < src_end)
|
||||||
audio->lin_buf_in[idxSample] = sample;
|
{
|
||||||
#endif
|
memcpy(dst, src, nBytesToCopy);
|
||||||
idxSample += CFG_TUD_AUDIO_TX_ITEMSIZE;
|
src = (uint8_t *)src + nBytesToCopy;
|
||||||
|
dst += nBytesToCopy * CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nSamplesPerChannelToSend * CFG_TUD_AUDIO_N_CHANNELS_TX * CFG_TUD_AUDIO_TX_ITEMSIZE;
|
}
|
||||||
|
|
||||||
|
return nSamplesPerFFToSend * CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO;
|
||||||
}
|
}
|
||||||
#endif //CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
|
#endif //CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
|
||||||
|
|
||||||
|
@ -685,9 +736,9 @@ void audiod_init(void)
|
||||||
|
|
||||||
// Initialize TX support FIFOs if required
|
// Initialize TX support FIFOs if required
|
||||||
#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
|
#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
|
||||||
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_TX; cnt++)
|
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; cnt++)
|
||||||
{
|
{
|
||||||
tu_fifo_config(&audio->tx_supp_ff[cnt], &audio->tx_supp_ff_buf[cnt], CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE, 1, true);
|
tu_fifo_config(&audio->tx_supp_ff[cnt], &audio->tx_supp_ff_buf[cnt], CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX, true);
|
||||||
#if CFG_FIFO_MUTEX
|
#if CFG_FIFO_MUTEX
|
||||||
tu_fifo_config_mutex(&audio->tx_supp_ff[cnt], osal_mutex_create(&audio->tx_supp_ff_mutex_wr[cnt]), NULL);
|
tu_fifo_config_mutex(&audio->tx_supp_ff[cnt], osal_mutex_create(&audio->tx_supp_ff_mutex_wr[cnt]), NULL);
|
||||||
#endif
|
#endif
|
||||||
|
@ -696,9 +747,9 @@ void audiod_init(void)
|
||||||
|
|
||||||
// Initialize RX support FIFOs if required
|
// Initialize RX support FIFOs if required
|
||||||
#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
|
#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
|
||||||
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_RX; cnt++)
|
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; cnt++)
|
||||||
{
|
{
|
||||||
tu_fifo_config(&audio->rx_supp_ff[cnt], &audio->rx_supp_ff_buf[cnt], CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE, 1, true);
|
tu_fifo_config(&audio->rx_supp_ff[cnt], &audio->rx_supp_ff_buf[cnt], CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX, true);
|
||||||
#if CFG_FIFO_MUTEX
|
#if CFG_FIFO_MUTEX
|
||||||
tu_fifo_config_mutex(&audio->rx_supp_ff[cnt], NULL, osal_mutex_create(&audio->rx_supp_ff_mutex_rd[cnt]));
|
tu_fifo_config_mutex(&audio->rx_supp_ff[cnt], NULL, osal_mutex_create(&audio->rx_supp_ff_mutex_rd[cnt]));
|
||||||
#endif
|
#endif
|
||||||
|
@ -725,14 +776,14 @@ void audiod_reset(uint8_t rhport)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
|
#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
|
||||||
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_TX; cnt++)
|
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO; cnt++)
|
||||||
{
|
{
|
||||||
tu_fifo_clear(&audio->tx_supp_ff[cnt]);
|
tu_fifo_clear(&audio->tx_supp_ff[cnt]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
|
#if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
|
||||||
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_RX; cnt++)
|
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO; cnt++)
|
||||||
{
|
{
|
||||||
tu_fifo_clear(&audio->rx_supp_ff[cnt]);
|
tu_fifo_clear(&audio->rx_supp_ff[cnt]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
#error You must define an audio class control request buffer size!
|
#error You must define an audio class control request buffer size!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// End point sizes - Limits: Full Speed <= 1023, High Speed <= 1024
|
// End point sizes IN BYTES - Limits: Full Speed <= 1023, High Speed <= 1024
|
||||||
#ifndef CFG_TUD_AUDIO_EPSIZE_IN
|
#ifndef CFG_TUD_AUDIO_EPSIZE_IN
|
||||||
#define CFG_TUD_AUDIO_EPSIZE_IN 0 // TX
|
#define CFG_TUD_AUDIO_EPSIZE_IN 0 // TX
|
||||||
#endif
|
#endif
|
||||||
|
@ -76,13 +76,13 @@
|
||||||
#define CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE 0
|
#define CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// General information of number of TX and/or RX channels - is used in case support FIFOs (see below) are used and can be used for descriptor definitions
|
// General information of number of TX and/or RX channels - is used in combination with support FIFOs (see below) and can be used for descriptor definitions
|
||||||
#ifndef CFG_TUD_AUDIO_N_CHANNELS_TX
|
#ifndef CFG_TUD_AUDIO_N_CHANNELS_TX
|
||||||
#define CFG_TUD_AUDIO_N_CHANNELS_TX 0
|
#define CFG_TUD_AUDIO_N_CHANNELS_TX 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CFG_TUD_AUDIO_N_CHANNELS_RX
|
#ifndef CFG_TUD_AUDIO_N_CHANNELS_RX
|
||||||
#define CFG_TUD_AUDIO_N_CHANNELS_RX 0
|
#define CFG_TUD_AUDIO_N_CHANNELS_RX 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Use of TX/RX support FIFOs
|
// Use of TX/RX support FIFOs
|
||||||
|
@ -104,7 +104,7 @@
|
||||||
// The encoding/decoding starts when the private callback functions
|
// The encoding/decoding starts when the private callback functions
|
||||||
// - audio_tx_done_cb()
|
// - audio_tx_done_cb()
|
||||||
// - audio_rx_done_cb()
|
// - audio_rx_done_cb()
|
||||||
// are invoked. If support FIFOs are used the corresponding encoding/decoding functions are called from there.
|
// are invoked. If support FIFOs are used, the corresponding encoding/decoding functions are called from there.
|
||||||
// Once encoding/decoding is done the result is put directly into the EP_X_SW_BUFFER_FIFOs. You can use the public callback functions
|
// Once encoding/decoding is done the result is put directly into the EP_X_SW_BUFFER_FIFOs. You can use the public callback functions
|
||||||
// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb()
|
// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb()
|
||||||
// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb()
|
// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb()
|
||||||
|
@ -120,13 +120,31 @@
|
||||||
// - audio_rx_done_cb()
|
// - audio_rx_done_cb()
|
||||||
// functions.
|
// functions.
|
||||||
|
|
||||||
// Size of support FIFOs - if size > 0 there are as many FIFOs set up as TX/RX channels defined
|
// The number of support FIFOs and number of channels is decoupled. The PCM encoding/decoding works depending on the ratio CFG_TUD_AUDIO_N_CHANNELS_XX / CFG_TUD_AUDIO_N_XX_SUPPORT_SW_FIFO, where currently 1:1 and 2:1 is implemented. The version 2:1 is useful in case of I2S for which usually 2 are channels already interleaved available.
|
||||||
|
|
||||||
|
// Size of support FIFOs IN SAMPLES - if size > 0 there are as many FIFOs set up as CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO and CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO
|
||||||
#ifndef CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
|
#ifndef CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
|
||||||
#define CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE 0 // Buffer size per channel - minimum size: ceil(f_s/1000)*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX
|
#define CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE 0 // FIFO size - minimum size: // ceil(f_s/1000) * CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
|
#ifndef CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
|
||||||
#define CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE 0 // Buffer size per channel - minimum size: ceil(f_s/1000)*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX
|
#define CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE 0 // FIFO size - minimum size: ceil(f_s/1000) * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX / CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO
|
||||||
|
#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
|
||||||
|
#define CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO CFG_TUD_AUDIO_N_CHANNELS_TX // default size is equal to number of channels
|
||||||
|
#else
|
||||||
|
#define CFG_TUD_AUDIO_N_TX_SUPPORT_SW_FIFO 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO
|
||||||
|
#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
|
||||||
|
#define CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO CFG_TUD_AUDIO_N_CHANNELS_RX // default size is equal to number of channels
|
||||||
|
#else
|
||||||
|
#define CFG_TUD_AUDIO_N_RX_SUPPORT_SW_FIFO 0
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Enable/disable feedback EP (required for asynchronous RX applications)
|
// Enable/disable feedback EP (required for asynchronous RX applications)
|
||||||
|
@ -167,20 +185,6 @@
|
||||||
#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 1
|
#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CFG_TUD_AUDIO_TX_ITEMSIZE
|
|
||||||
#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == 1
|
|
||||||
#define CFG_TUD_AUDIO_TX_ITEMSIZE 1
|
|
||||||
#elif CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == 2
|
|
||||||
#define CFG_TUD_AUDIO_TX_ITEMSIZE 2
|
|
||||||
#else
|
|
||||||
#define CFG_TUD_AUDIO_TX_ITEMSIZE 4
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CFG_TUD_AUDIO_TX_ITEMSIZE < CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX
|
|
||||||
#error FIFO element size (ITEMSIZE) must not be smaller then sample size
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CFG_TUD_AUDIO_FORMAT_TYPE_RX == AUDIO_FORMAT_TYPE_I
|
#if CFG_TUD_AUDIO_FORMAT_TYPE_RX == AUDIO_FORMAT_TYPE_I
|
||||||
|
@ -193,26 +197,6 @@
|
||||||
#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX 1
|
#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX == 1
|
|
||||||
#define CFG_TUD_AUDIO_RX_ITEMSIZE 1
|
|
||||||
#elif CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX == 2
|
|
||||||
#define CFG_TUD_AUDIO_RX_ITEMSIZE 2
|
|
||||||
#else
|
|
||||||
#define CFG_TUD_AUDIO_RX_ITEMSIZE 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// In case PCM encoding/decoding of 24 into 32 bits, the adjustment needs to be defined
|
|
||||||
#define CFG_TUD_AUDIO_LEFT_JUSTIFIED
|
|
||||||
#define CFG_TUD_AUDIO_RIGHT_JUSTIFIED
|
|
||||||
|
|
||||||
#ifndef CFG_TUD_AUDIO_JUSTIFICATION_RX
|
|
||||||
#define CFG_TUD_AUDIO_JUSTIFICATION_RX CFG_TUD_AUDIO_LEFT_JUSTIFIED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CFG_TUD_AUDIO_JUSTIFICATION_TX
|
|
||||||
#define CFG_TUD_AUDIO_JUSTIFICATION_TX CFG_TUD_AUDIO_LEFT_JUSTIFIED
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//static_assert(sizeof(tud_audio_desc_lengths) != CFG_TUD_AUDIO, "Supply audio function descriptor pack length!");
|
//static_assert(sizeof(tud_audio_desc_lengths) != CFG_TUD_AUDIO, "Supply audio function descriptor pack length!");
|
||||||
|
|
|
@ -596,42 +596,6 @@ uint16_t tu_fifo_read_n_const_addr(tu_fifo_t* f, void * buffer, uint16_t n)
|
||||||
return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_CST);
|
return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_CST);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
/*!
|
|
||||||
@brief This function will read n elements from the array index specified by
|
|
||||||
the read pointer and increment the read index. It copies the elements
|
|
||||||
into another FIFO and as such takes care of wraps etc.
|
|
||||||
This function checks for an overflow and corrects read pointer if required.
|
|
||||||
|
|
||||||
@param[in] f
|
|
||||||
Pointer to the FIFO buffer to manipulate
|
|
||||||
@param[in] f_target
|
|
||||||
Pointer to target FIFO i.e. to copy into
|
|
||||||
@param[in] offset
|
|
||||||
Position to read from in the FIFO buffer with respect to read pointer
|
|
||||||
@param[in] n
|
|
||||||
Number of items to peek
|
|
||||||
|
|
||||||
@returns number of items read from the FIFO
|
|
||||||
*/
|
|
||||||
/******************************************************************************/
|
|
||||||
uint16_t tu_fifo_read_n_into_other_fifo(tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n)
|
|
||||||
{
|
|
||||||
tu_fifo_lock(f->mutex_rd);
|
|
||||||
tu_fifo_lock(f_target->mutex_wr);
|
|
||||||
|
|
||||||
// Conduct copy
|
|
||||||
n = tu_fifo_peek_n_into_other_fifo(f, f_target, offset, n);
|
|
||||||
|
|
||||||
// Advance read pointer
|
|
||||||
f->rd_idx = advance_pointer(f, f->rd_idx, n);
|
|
||||||
|
|
||||||
tu_fifo_unlock(f->mutex_rd);
|
|
||||||
tu_fifo_unlock(f_target->mutex_wr);
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/*!
|
/*!
|
||||||
@brief Read one item without removing it from the FIFO.
|
@brief Read one item without removing it from the FIFO.
|
||||||
|
@ -680,92 +644,6 @@ uint16_t tu_fifo_peek_at_n(tu_fifo_t* f, uint16_t offset, void * p_buffer, uint1
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
/*!
|
|
||||||
@brief Read n items without removing it from the FIFO and copy them into another FIFO.
|
|
||||||
This function checks for an overflow and corrects read pointer if required.
|
|
||||||
|
|
||||||
@param[in] f
|
|
||||||
Pointer to the FIFO buffer to manipulate
|
|
||||||
@param[in] f_target
|
|
||||||
Pointer to target FIFO i.e. to copy into
|
|
||||||
@param[in] offset
|
|
||||||
Position to read from in the FIFO buffer with respect to read pointer
|
|
||||||
@param[in] n
|
|
||||||
Number of items to peek
|
|
||||||
|
|
||||||
@returns Number of bytes written to p_buffer
|
|
||||||
*/
|
|
||||||
/******************************************************************************/
|
|
||||||
uint16_t tu_fifo_peek_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n)
|
|
||||||
{
|
|
||||||
// Copy is only possible if both FIFOs have common element size
|
|
||||||
TU_VERIFY(f->item_size == f_target->item_size);
|
|
||||||
|
|
||||||
// Work on local copies on case any pointer changes in between (only necessary if something is written into FIFO f in the meantime)
|
|
||||||
uint16_t f_wr_idx = f->wr_idx;
|
|
||||||
uint16_t f_rd_idx = f->rd_idx;
|
|
||||||
|
|
||||||
uint16_t cnt = _tu_fifo_count(f, f_wr_idx, f_rd_idx);
|
|
||||||
|
|
||||||
// Check overflow and correct if required
|
|
||||||
if (cnt > f->depth)
|
|
||||||
{
|
|
||||||
_tu_fifo_correct_read_pointer(f, f->wr_idx);
|
|
||||||
f_rd_idx = f->rd_idx;
|
|
||||||
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;
|
|
||||||
|
|
||||||
tu_fifo_lock(f_target->mutex_wr); // Lock both read and write pointers - in case of an overwritable FIFO both may be modified
|
|
||||||
|
|
||||||
uint16_t wr_rel_tgt = get_relative_pointer(f_target, f_target->wr_idx, 0);
|
|
||||||
|
|
||||||
if (!f_target->overwritable)
|
|
||||||
{
|
|
||||||
// Not overwritable limit up to full
|
|
||||||
n = tu_min16(n, tu_fifo_remaining(f_target));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advance write pointer - not required for later
|
|
||||||
f_target->wr_idx = advance_pointer(f_target, f_target->wr_idx, n);
|
|
||||||
|
|
||||||
if (n >= f_target->depth)
|
|
||||||
{
|
|
||||||
offset += n - f_target->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!
|
|
||||||
wr_rel_tgt = get_relative_pointer(f_target, f_target->rd_idx, 0);
|
|
||||||
|
|
||||||
n = f_target->depth;
|
|
||||||
|
|
||||||
// Update write pointer
|
|
||||||
f_target->wr_idx = advance_pointer(f_target, f_target->rd_idx, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy linear size
|
|
||||||
uint16_t sz = f_target->depth - wr_rel_tgt;
|
|
||||||
_tu_fifo_peek_at_n(f, offset, &f_target->buffer[wr_rel_tgt], sz, f_wr_idx, f_rd_idx, TU_FIFO_COPY_INC);
|
|
||||||
|
|
||||||
if (n > sz)
|
|
||||||
{
|
|
||||||
// Copy remaining, now wrapped part, into target buffer
|
|
||||||
_tu_fifo_peek_at_n(f, offset + sz, f_target->buffer, n-sz, f_wr_idx, f_rd_idx, TU_FIFO_COPY_INC);
|
|
||||||
}
|
|
||||||
|
|
||||||
tu_fifo_unlock(f_target->mutex_wr);
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/*!
|
/*!
|
||||||
@brief Write one element into the buffer.
|
@brief Write one element into the buffer.
|
||||||
|
@ -976,7 +854,7 @@ void tu_fifo_backward_read_pointer(tu_fifo_t *f, uint16_t n)
|
||||||
Returns the length and pointer from which bytes can be read in a linear manner.
|
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
|
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
|
corresponding pointer is invalid. The returned length is limited to the number
|
||||||
of BYTES n which the user wants to write into the buffer.
|
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
|
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
|
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
|
and you need to execute this function a second time to get a pointer to the
|
||||||
|
@ -984,13 +862,13 @@ void tu_fifo_backward_read_pointer(tu_fifo_t *f, uint16_t n)
|
||||||
@param[in] f
|
@param[in] f
|
||||||
Pointer to FIFO
|
Pointer to FIFO
|
||||||
@param[in] offset
|
@param[in] offset
|
||||||
Number of BYTES to ignore before start writing
|
Number of ITEMS to ignore before start writing
|
||||||
@param[out] **ptr
|
@param[out] **ptr
|
||||||
Pointer to start writing to
|
Pointer to start writing to
|
||||||
@param[in] n
|
@param[in] n
|
||||||
Number of BYTES to read from buffer
|
Number of ITEMS to read from buffer
|
||||||
@return len
|
@return len
|
||||||
Length of linear part IN BYTES, if zero corresponding pointer ptr is invalid
|
Length of linear part IN ITEMS, 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)
|
uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr, uint16_t n)
|
||||||
|
@ -1010,9 +888,6 @@ uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr,
|
||||||
cnt = f->depth;
|
cnt = f->depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to bytes
|
|
||||||
cnt = cnt * f->item_size;
|
|
||||||
|
|
||||||
// Skip beginning of buffer
|
// Skip beginning of buffer
|
||||||
if (cnt == 0 || offset >= cnt) return 0;
|
if (cnt == 0 || offset >= cnt) return 0;
|
||||||
|
|
||||||
|
@ -1027,16 +902,14 @@ uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr,
|
||||||
// Check if there is a wrap around necessary
|
// Check if there is a wrap around necessary
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
|
|
||||||
if (w >= r) {
|
if (w > r) {
|
||||||
len = w - r;
|
len = w - r;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
len = f->depth - r;
|
len = f->depth - r; // Also the case if FIFO was full
|
||||||
}
|
}
|
||||||
|
|
||||||
len = len * f->item_size;
|
|
||||||
|
|
||||||
// Limit to required length
|
// Limit to required length
|
||||||
len = tu_min16(n, len);
|
len = tu_min16(n, len);
|
||||||
|
|
||||||
|
@ -1060,31 +933,31 @@ uint16_t tu_fifo_get_linear_read_info(tu_fifo_t *f, uint16_t offset, void **ptr,
|
||||||
@param[in] f
|
@param[in] f
|
||||||
Pointer to FIFO
|
Pointer to FIFO
|
||||||
@param[in] offset
|
@param[in] offset
|
||||||
Number of bytes to ignore before start writing
|
Number of ITEMS to ignore before start writing
|
||||||
@param[out] **ptr
|
@param[out] **ptr
|
||||||
Pointer to start writing to
|
Pointer to start writing to
|
||||||
@param[in] n
|
@param[in] n
|
||||||
Number of BYTES to write into buffer
|
Number of ITEMS to write into buffer
|
||||||
@return len
|
@return len
|
||||||
Length of linear part IN BYTES, if zero corresponding pointer ptr is invalid
|
Length of linear part IN ITEMS, 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 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 w = f->wr_idx, r = f->rd_idx;
|
||||||
uint16_t free = _tu_fifo_remaining(f, w, r) * f->item_size;
|
uint16_t free = _tu_fifo_remaining(f, w, r);
|
||||||
|
|
||||||
if (!f->overwritable)
|
if (!f->overwritable)
|
||||||
{
|
{
|
||||||
// Not overwritable limit up to full
|
// Not overwritable limit up to full
|
||||||
n = tu_min16(n, free);
|
n = tu_min16(n, free);
|
||||||
}
|
}
|
||||||
else if (n >= f->depth * f->item_size)
|
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
|
// 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);
|
TU_VERIFY(n <= 2*f->depth);
|
||||||
|
|
||||||
n = f->depth * f->item_size;
|
n = f->depth;
|
||||||
// We start writing at the read pointer's position since we fill the complete
|
// 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!
|
// 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!
|
// This would end up in a race condition with read functions!
|
||||||
|
@ -1108,8 +981,6 @@ uint16_t tu_fifo_get_linear_write_info(tu_fifo_t *f, uint16_t offset, void **ptr
|
||||||
len = f->depth - w;
|
len = f->depth - w;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = len * f->item_size;
|
|
||||||
|
|
||||||
// Limit to required length
|
// Limit to required length
|
||||||
len = tu_min16(n, len);
|
len = tu_min16(n, len);
|
||||||
|
|
||||||
|
|
|
@ -113,11 +113,9 @@ uint16_t tu_fifo_write_n_const_addr (tu_fifo_t* f, const void * dat
|
||||||
bool tu_fifo_read (tu_fifo_t* f, void * p_buffer);
|
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 (tu_fifo_t* f, void * p_buffer, uint16_t n);
|
||||||
uint16_t tu_fifo_read_n_const_addr (tu_fifo_t* f, void * buffer, uint16_t n);
|
uint16_t tu_fifo_read_n_const_addr (tu_fifo_t* f, void * buffer, uint16_t n);
|
||||||
uint16_t tu_fifo_read_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n);
|
|
||||||
|
|
||||||
bool tu_fifo_peek_at (tu_fifo_t* f, uint16_t pos, void * p_buffer);
|
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);
|
uint16_t tu_fifo_peek_at_n (tu_fifo_t* f, uint16_t pos, void * p_buffer, uint16_t n);
|
||||||
uint16_t tu_fifo_peek_n_into_other_fifo (tu_fifo_t* f, tu_fifo_t* f_target, uint16_t offset, uint16_t n);
|
|
||||||
|
|
||||||
uint16_t tu_fifo_count (tu_fifo_t* f);
|
uint16_t tu_fifo_count (tu_fifo_t* f);
|
||||||
bool tu_fifo_empty (tu_fifo_t* f);
|
bool tu_fifo_empty (tu_fifo_t* f);
|
||||||
|
|
Loading…
Reference in New Issue