Merge pull request #3 from hathach/PanRe-uac2-fix-build

Pan re uac2 fix build
This commit is contained in:
PanRe 2020-10-07 10:19:58 +02:00 committed by GitHub
commit 230c93a641
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 966 additions and 467 deletions

View File

@ -27,6 +27,7 @@ jobs:
fail-fast: false
matrix:
example:
- 'device/audio_test'
- 'device/board_test'
- 'device/cdc_dual_ports'
- 'device/cdc_msc'

View File

@ -137,6 +137,7 @@ void audio_task(void)
bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
{
(void) rhport;
(void) pBuff;
// We do not support any set range requests here, only current value requests
TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
@ -146,6 +147,8 @@ bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_re
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
uint8_t ep = TU_U16_LOW(p_request->wIndex);
(void) channelNum; (void) ctrlSel; (void) ep;
return false; // Yet not implemented
}
@ -153,6 +156,7 @@ bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_re
bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
{
(void) rhport;
(void) pBuff;
// We do not support any set range requests here, only current value requests
TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
@ -162,6 +166,8 @@ bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_r
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
uint8_t itf = TU_U16_LOW(p_request->wIndex);
(void) channelNum; (void) ctrlSel; (void) itf;
return false; // Yet not implemented
}
@ -176,39 +182,43 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *
uint8_t itf = TU_U16_LOW(p_request->wIndex);
uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
(void) itf;
// We do not support any set range requests here, only current value requests
TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
// If request is for our feature unit
if (entityID == 2)
if ( entityID == 2 )
{
switch (ctrlSel)
switch ( ctrlSel )
{
case AUDIO_FU_CTRL_MUTE:
// Request uses format layout 1
TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t));
// Request uses format layout 1
TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t));
mute[channelNum] = ((audio_control_cur_1_t *)pBuff)->bCur;
mute[channelNum] = ((audio_control_cur_1_t*) pBuff)->bCur;
TU_LOG2(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum);
TU_LOG2(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum);
return true;
return true;
case AUDIO_FU_CTRL_VOLUME:
// Request uses format layout 2
TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t));
// Request uses format layout 2
TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t));
volume[channelNum] = ((audio_control_cur_2_t *)pBuff)->bCur;
volume[channelNum] = ((audio_control_cur_2_t*) pBuff)->bCur;
TU_LOG2(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum);
TU_LOG2(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum);
return true;
return true;
// Unknown/Unsupported control
default: TU_BREAKPOINT(); return false;
// Unknown/Unsupported control
default:
TU_BREAKPOINT();
return false;
}
}
return false; // Yet not implemented
return false; // Yet not implemented
}
// Invoked when audio class specific get request received for an EP
@ -221,6 +231,8 @@ bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_re
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
uint8_t ep = TU_U16_LOW(p_request->wIndex);
(void) channelNum; (void) ctrlSel; (void) ep;
// return tud_control_xfer(rhport, p_request, &tmp, 1);
return false; // Yet not implemented
@ -236,6 +248,8 @@ bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_r
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
uint8_t itf = TU_U16_LOW(p_request->wIndex);
(void) channelNum; (void) ctrlSel; (void) itf;
return false; // Yet not implemented
}

View File

@ -33,6 +33,7 @@ SRC_C += \
src/common/tusb_fifo.c \
src/device/usbd.c \
src/device/usbd_control.c \
src/class/audio/audio_device.c \
src/class/cdc/cdc_device.c \
src/class/dfu/dfu_rt_device.c \
src/class/hid/hid_device.c \

View File

@ -469,28 +469,44 @@ typedef enum
/// Additional Audio Device Class Codes - Source: Audio Data Formats
/// A.1 - Audio Class-Format Type Codes UAC2
typedef enum
{
AUDIO_FORMAT_TYPE_UNDEFINED = 0x00,
AUDIO_FORMAT_TYPE_I = 0x01,
AUDIO_FORMAT_TYPE_II = 0x02,
AUDIO_FORMAT_TYPE_III = 0x03,
AUDIO_FORMAT_TYPE_IV = 0x04,
AUDIO_EXT_FORMAT_TYPE_I = 0x81,
AUDIO_EXT_FORMAT_TYPE_II = 0x82,
AUDIO_EXT_FORMAT_TYPE_III = 0x83,
} audio_format_type_t;
//typedef enum
//{
// AUDIO_FORMAT_TYPE_UNDEFINED = 0x00,
// AUDIO_FORMAT_TYPE_I = 0x01,
// AUDIO_FORMAT_TYPE_II = 0x02,
// AUDIO_FORMAT_TYPE_III = 0x03,
// AUDIO_FORMAT_TYPE_IV = 0x04,
// AUDIO_EXT_FORMAT_TYPE_I = 0x81,
// AUDIO_EXT_FORMAT_TYPE_II = 0x82,
// AUDIO_EXT_FORMAT_TYPE_III = 0x83,
//} audio_format_type_t;
#define AUDIO_FORMAT_TYPE_UNDEFINED 0x00
#define AUDIO_FORMAT_TYPE_I 0x01
#define AUDIO_FORMAT_TYPE_II 0x02
#define AUDIO_FORMAT_TYPE_III 0x03
#define AUDIO_FORMAT_TYPE_IV 0x04
#define AUDIO_EXT_FORMAT_TYPE_I 0x81
#define AUDIO_EXT_FORMAT_TYPE_II 0x82
#define AUDIO_EXT_FORMAT_TYPE_III 0x83
/// A.2.1 - Audio Class-Audio Data Format Type I UAC2
typedef enum
{
AUDIO_DATA_FORMAT_TYPE_I_PCM = (uint32_t) (1 << 0),
AUDIO_DATA_FORMAT_TYPE_I_PCM8 = (uint32_t) (1 << 1),
AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT = (uint32_t) (1 << 2),
AUDIO_DATA_FORMAT_TYPE_I_ALAW = (uint32_t) (1 << 3),
AUDIO_DATA_FORMAT_TYPE_I_MULAW = (uint32_t) (1 << 4),
AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA = 0x100000000,
} audio_data_format_type_I_t;
//typedef enum
//{
// AUDIO_DATA_FORMAT_TYPE_I_PCM = (uint32_t) (1 << 0),
// AUDIO_DATA_FORMAT_TYPE_I_PCM8 = (uint32_t) (1 << 1),
// AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT = (uint32_t) (1 << 2),
// AUDIO_DATA_FORMAT_TYPE_I_ALAW = (uint32_t) (1 << 3),
// AUDIO_DATA_FORMAT_TYPE_I_MULAW = (uint32_t) (1 << 4),
// AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA = 0x100000000,
//} audio_data_format_type_I_t;
#define AUDIO_DATA_FORMAT_TYPE_I_PCM ((uint32_t) (1 << 0))
#define AUDIO_DATA_FORMAT_TYPE_I_PCM8 ((uint32_t) (1 << 1))
#define AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT ((uint32_t) (1 << 2))
#define AUDIO_DATA_FORMAT_TYPE_I_ALAW ((uint32_t) (1 << 3))
#define AUDIO_DATA_FORMAT_TYPE_I_MULAW ((uint32_t) (1 << 4))
#define AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA 0x100000000
/// All remaining definitions are taken from the descriptor descriptions in the UAC2 main specification

View File

@ -564,9 +564,10 @@ static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t*
for (cntChannel = 1; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_TX; cntChannel++)
{
if (audio->tx_ff[cntChannel].count / CFG_TUD_AUDIO_TX_ITEMSIZE < nSamplesPerChannelToSend)
uint16_t const count = tu_fifo_count(&audio->tx_ff[cntChannel]);
if (count / CFG_TUD_AUDIO_TX_ITEMSIZE < nSamplesPerChannelToSend)
{
nSamplesPerChannelToSend = audio->tx_ff[cntChannel].count * CFG_TUD_AUDIO_TX_ITEMSIZE;
nSamplesPerChannelToSend = count * CFG_TUD_AUDIO_TX_ITEMSIZE;
}
}
@ -782,6 +783,8 @@ void audiod_reset(uint8_t rhport)
uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
{
(void) max_len;
TU_VERIFY ( TUSB_CLASS_AUDIO == itf_desc->bInterfaceClass &&
AUDIO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass);
@ -1171,6 +1174,7 @@ bool audiod_control_request(uint8_t rhport, tusb_control_request_t const * p_req
bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
{
(void) result;
(void) xferred_bytes;
// Search for interface belonging to given end point address and proceed as required
uint8_t idxDriver;

View File

@ -33,7 +33,6 @@
#include "device/usbd.h"
#include "audio.h"
#include "tusb_config.h"
//--------------------------------------------------------------------+
// Class Driver Configuration
@ -59,6 +58,10 @@
#define CFG_TUD_AUDIO_TX_FIFO_SIZE 0 // Buffer size per channel
#endif
#ifndef CFG_TUD_AUDIO_TX_DMA_RINGBUFFER_SIZE
#define CFG_TUD_AUDIO_TX_DMA_RINGBUFFER_SIZE 0
#endif
#if CFG_TUD_AUDIO_TX_FIFO_SIZE && CFG_TUD_AUDIO_TX_DMA_RINGBUFFER_SIZE
#error TX_FIFOs and TX_DMA_RINGBUFFER can not be used simultaneously!
#endif
@ -193,6 +196,10 @@ uint16_t tud_audio_n_write_ep_in_buffer(uint8_t itf, const void * data, uint16_t
#endif
*/
#ifndef CFG_TUD_AUDIO_TX_FIFO_COUNT
#define CFG_TUD_AUDIO_TX_FIFO_COUNT 1
#endif
#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE
#if CFG_TUD_AUDIO_TX_FIFO_COUNT > 1
uint16_t tud_audio_n_write (uint8_t itf, uint8_t channelId, const void * data, uint16_t len);

View File

@ -47,10 +47,10 @@
#define U16_TO_U8S_BE(u16) TU_U16_HIGH(u16), TU_U16_LOW(u16)
#define U16_TO_U8S_LE(u16) TU_U16_LOW(u16), TU_U16_HIGH(u16)
#define U32_B1_U8(u32) ((uint8_t) (((u32) >> 24) & 0x000000ff)) // MSB
#define U32_B2_U8(u32) ((uint8_t) (((u32) >> 16) & 0x000000ff))
#define U32_B3_U8(u32) ((uint8_t) (((u32) >> 8) & 0x000000ff))
#define U32_B4_U8(u32) ((uint8_t) ((u32) & 0x000000ff)) // LSB
#define U32_B1_U8(u32) ((uint8_t) ((((uint32_t) u32) >> 24) & 0x000000ff)) // MSB
#define U32_B2_U8(u32) ((uint8_t) ((((uint32_t) u32) >> 16) & 0x000000ff))
#define U32_B3_U8(u32) ((uint8_t) ((((uint32_t) u32) >> 8) & 0x000000ff))
#define U32_B4_U8(u32) ((uint8_t) (((uint32_t) u32) & 0x000000ff)) // LSB
#define U32_TO_U8S_BE(u32) U32_B1_U8(u32), U32_B2_U8(u32), U32_B3_U8(u32), U32_B4_U8(u32)
#define U32_TO_U8S_LE(u32) U32_B4_U8(u32), U32_B3_U8(u32), U32_B2_U8(u32), U32_B1_U8(u32)

View File

@ -2,6 +2,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
* Copyright (c) 2020 Reinhard Panhuber - rework to unmasked pointers
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -57,6 +58,8 @@ static void tu_fifo_unlock(tu_fifo_t *f)
bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable)
{
if (depth > 0x8000) return false; // Maximum depth is 2^15 items
tu_fifo_lock(f);
f->buffer = (uint8_t*) buffer;
@ -64,55 +67,328 @@ 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->rd_idx = f->wr_idx = f->count = 0;
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)
f->non_used_index_space = 0xFFFF - f->max_pointer_idx;
f->rd_idx = f->wr_idx = 0;
tu_fifo_unlock(f);
return true;
}
// Static functions are intended to work on local variables
static inline uint16_t _ff_mod(uint16_t idx, uint16_t depth)
{
return (idx < depth) ? idx : (idx-depth);
while ( idx >= depth) idx -= depth;
return idx;
}
// retrieve data from fifo
static inline void _ff_pull(tu_fifo_t* f, void * buffer, uint16_t n)
// send one item to FIFO WITHOUT updating write pointer
static inline void _ff_push(tu_fifo_t* f, void const * data, uint16_t wRel)
{
memcpy(buffer,
f->buffer + (f->rd_idx * f->item_size),
f->item_size*n);
f->rd_idx = _ff_mod(f->rd_idx + n, f->depth);
f->count -= n;
memcpy(f->buffer + (wRel * f->item_size), data, f->item_size);
}
// send data to fifo
static inline void _ff_push(tu_fifo_t* f, void const * data, uint16_t n)
// send n items to FIFO WITHOUT updating write pointer
static void _ff_push_n(tu_fifo_t* f, void const * data, uint16_t n, uint16_t wRel)
{
memcpy(f->buffer + (f->wr_idx * f->item_size),
data,
f->item_size*n);
f->wr_idx = _ff_mod(f->wr_idx + n, f->depth);
if (tu_fifo_full(f))
if(wRel + n <= f->depth) // Linear mode only
{
f->rd_idx = f->wr_idx; // keep the full state (rd == wr && count = depth)
memcpy(f->buffer + (wRel * f->item_size), data, n*f->item_size);
}
else // Wrap around
{
uint16_t nLin = f->depth - wRel;
// Write data to linear part of buffer
memcpy(f->buffer + (wRel * f->item_size), data, nLin*f->item_size);
// Write data wrapped around
memcpy(f->buffer, data + nLin*f->item_size, (n - nLin) * f->item_size);
}
}
// get one item from FIFO WITHOUT updating read pointer
static inline void _ff_pull(tu_fifo_t* f, void * p_buffer, uint16_t rRel)
{
memcpy(p_buffer, f->buffer + (rRel * f->item_size), f->item_size);
}
// get n items from FIFO WITHOUT updating read pointer
static void _ff_pull_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t rRel)
{
if(rRel + n <= f->depth) // Linear mode only
{
memcpy(p_buffer, f->buffer + (rRel * f->item_size), n*f->item_size);
}
else // Wrap around
{
uint16_t nLin = f->depth - rRel;
// Read data from linear part of buffer
memcpy(p_buffer, f->buffer + (rRel * f->item_size), nLin*f->item_size);
// Read data wrapped part
memcpy(p_buffer + nLin*f->item_size, f->buffer, (n - nLin) * f->item_size);
}
}
// Advance an absolute pointer
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
if ((p > p + offset) || (p + offset > f->max_pointer_idx))
{
p = (p + offset) + f->non_used_index_space;
}
else
{
f->count += n;
p += offset;
}
return p;
}
// Backward an absolute pointer
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
if ((p < p - offset) || (p - offset > f->max_pointer_idx))
{
p = (p - offset) - f->non_used_index_space;
}
else
{
p -= offset;
}
return p;
}
// get relative from absolute pointer
static uint16_t get_relative_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset)
{
return _ff_mod(advance_pointer(f, p, offset), f->depth);
}
// Works on local copies of w and r
static inline uint16_t _tu_fifo_count(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs)
{
uint16_t cnt = wAbs-rAbs;
// In case we have non-power of two depth we need a further modification
if (rAbs > wAbs) cnt -= f->non_used_index_space;
return cnt;
}
// Works on local copies of w and r
static inline bool _tu_fifo_empty(uint16_t wAbs, uint16_t rAbs)
{
return wAbs == rAbs;
}
// Works on local copies of w and r
static inline bool _tu_fifo_full(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs)
{
return (_tu_fifo_count(f, wAbs, rAbs) == f->depth);
}
// Works on local copies of w and r
// BE AWARE - THIS FUNCTION MIGHT NOT GIVE A CORRECT ANSWERE IN CASE WRITE POINTER "OVERFLOWS"
// Only one overflow is allowed for this function to work e.g. if depth = 100, you must not
// write more than 2*depth-1 items in one rush without updating write pointer. Otherwise
// write pointer wraps and you pointer states are messed up. This can only happen if you
// use DMAs, write functions do not allow such an error.
static inline bool _tu_fifo_overflowed(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs)
{
return (_tu_fifo_count(f, wAbs, rAbs) > f->depth);
}
// Works on local copies of w
// For more details see _tu_fifo_overflow()!
static inline void _tu_fifo_correct_read_pointer(tu_fifo_t* f, uint16_t wAbs)
{
f->rd_idx = backward_pointer(f, wAbs, f->depth);
}
// 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)
{
uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs);
// Check overflow and correct if required
if (cnt > f->depth)
{
_tu_fifo_correct_read_pointer(f, wAbs);
cnt = f->depth;
}
// Skip beginning of buffer
if (cnt == 0 || offset >= cnt) return false;
uint16_t rRel = get_relative_pointer(f, rAbs, offset);
// Peek data
_ff_pull(f, p_buffer, rRel);
return true;
}
// 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)
{
uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs);
// Check overflow and correct if required
if (cnt > f->depth)
{
_tu_fifo_correct_read_pointer(f, wAbs);
rAbs = 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) {
if (cnt == 0) return 0;
n = cnt;
}
uint16_t rRel = get_relative_pointer(f, rAbs, offset);
// Peek data
_ff_pull_n(f, p_buffer, n, rRel);
return n;
}
// Works on local copies of w and r
static inline uint16_t _tu_fifo_remaining(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs)
{
return f->depth - _tu_fifo_count(f, wAbs, rAbs);
}
/******************************************************************************/
/*!
@brief Read one element out of the RX buffer.
@brief Get number of items in FIFO.
As this function only reads the read and write pointers once, this function is
reentrant and thus thread and ISR save without any mutexes.
@param[in] f
Pointer to the FIFO buffer to manipulate
@returns Number of items in FIFO
*/
/******************************************************************************/
uint16_t tu_fifo_count(tu_fifo_t* f)
{
return _tu_fifo_count(f, f->wr_idx, f->rd_idx);
}
/******************************************************************************/
/*!
@brief Check if FIFO is empty.
As this function only reads the read and write pointers once, this function is
reentrant and thus thread and ISR save without any mutexes.
@param[in] f
Pointer to the FIFO buffer to manipulate
@returns Number of items in FIFO
*/
/******************************************************************************/
bool tu_fifo_empty(tu_fifo_t* f)
{
return _tu_fifo_empty(f->wr_idx, f->rd_idx);
}
/******************************************************************************/
/*!
@brief Check if FIFO is full.
As this function only reads the read and write pointers once, this function is
reentrant and thus thread and ISR save without any mutexes.
@param[in] f
Pointer to the FIFO buffer to manipulate
@returns Number of items in FIFO
*/
/******************************************************************************/
bool tu_fifo_full(tu_fifo_t* f)
{
return _tu_fifo_full(f, f->wr_idx, f->rd_idx);
}
/******************************************************************************/
/*!
@brief Get remaining space in FIFO.
As this function only reads the read and write pointers once, this function is
reentrant and thus thread and ISR save without any mutexes.
@param[in] f
Pointer to the FIFO buffer to manipulate
@returns Number of items in FIFO
*/
/******************************************************************************/
uint16_t tu_fifo_remaining(tu_fifo_t* f)
{
return _tu_fifo_remaining(f, f->wr_idx, f->rd_idx);
}
/******************************************************************************/
/*!
@brief Check if overflow happened.
BE AWARE - THIS FUNCTION MIGHT NOT GIVE A CORRECT ANSWERE IN CASE WRITE POINTER "OVERFLOWS"
Only one overflow is allowed for this function to work e.g. if depth = 100, you must not
write more than 2*depth-1 items in one rush without updating write pointer. Otherwise
write pointer wraps and you pointer states are messed up. This can only happen if you
use DMAs, write functions do not allow such an error. Avoid such nasty things!
All reading functions (read, peek) check for overflows and correct read pointer on their own such
that latest items are read.
If required (e.g. for DMA use) you can also correct the read pointer by
tu_fifo_correct_read_pointer().
@param[in] f
Pointer to the FIFO buffer to manipulate
@returns True if overflow happened
*/
/******************************************************************************/
bool tu_fifo_overflowed(tu_fifo_t* f)
{
return _tu_fifo_overflowed(f, f->wr_idx, f->rd_idx);
}
// Only use in case tu_fifo_overflow() returned true!
void tu_fifo_correct_read_pointer(tu_fifo_t* f)
{
tu_fifo_lock(f);
_tu_fifo_correct_read_pointer(f, f->wr_idx);
tu_fifo_unlock(f);
}
/******************************************************************************/
/*!
@brief Read one element out of the buffer.
This function will return the element located at the array index of the
read pointer, and then increment the read pointer index. If the read
pointer exceeds the maximum buffer size, it will roll over to zero.
read pointer, and then increment the read pointer index.
This function checks for an overflow and corrects read pointer if required.
@param[in] f
Pointer to the FIFO buffer to manipulate
@ -120,26 +396,27 @@ static inline void _ff_push(tu_fifo_t* f, void const * data, uint16_t n)
Pointer to the place holder for data read from the buffer
@returns TRUE if the queue is not empty
*/
*/
/******************************************************************************/
bool tu_fifo_read(tu_fifo_t* f, void * buffer)
{
if( tu_fifo_empty(f) ) return false;
tu_fifo_lock(f); // TODO: Here we may distinguish for read and write pointer mutexes!
tu_fifo_lock(f);
// 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
_ff_pull(f, buffer, 1);
// Advance pointer
f->rd_idx = advance_pointer(f, f->rd_idx, ret);
tu_fifo_unlock(f);
return true;
return ret;
}
/******************************************************************************/
/*!
@brief This function will read n elements from the array index specified by
the read pointer and increment the read index. If the read index
exceeds the max buffer size, then it will roll over to zero.
the read pointer and increment the read index.
This function checks for an overflow and corrects read pointer if required.
@param[in] f
Pointer to the FIFO buffer to manipulate
@ -149,76 +426,76 @@ bool tu_fifo_read(tu_fifo_t* f, void * buffer)
Number of element that buffer can afford
@returns number of items read from the FIFO
*/
*/
/******************************************************************************/
uint16_t tu_fifo_read_n (tu_fifo_t* f, void * buffer, uint16_t count)
uint16_t tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t count)
{
if(tu_fifo_empty(f)) return 0;
tu_fifo_lock(f); // TODO: Here we may distinguish for read and write pointer mutexes!
tu_fifo_lock(f);
// Peek the data
count = _tu_fifo_peek_at_n(f, 0, buffer, count, 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
// Limit up to fifo's count
if(count > f->count) count = f->count;
if(count + f->rd_idx <= f->depth)
{
_ff_pull(f, buffer, count);
}
else
{
uint16_t const part1 = f->depth - f->rd_idx;
// Part 1: from rd_idx to end
_ff_pull(f, buffer, part1);
buffer = ((uint8_t*) buffer) + part1*f->item_size;
// Part 2: start to remaining
_ff_pull(f, buffer, count-part1);
}
// Advance read pointer
f->rd_idx = advance_pointer(f, f->rd_idx, count);
tu_fifo_unlock(f);
return count;
}
/******************************************************************************/
/*!
@brief Read one item without removing it from the FIFO
@brief Read one item without removing it from the 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] pos
Position to read from in the FIFO buffer
@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
@returns TRUE if the queue is not empty
*/
*/
/******************************************************************************/
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 offset, void * p_buffer)
{
if ( pos >= f->count ) return false;
tu_fifo_lock(f);
// rd_idx is pos=0
uint16_t index = _ff_mod(f->rd_idx + pos, f->depth);
memcpy(p_buffer,
f->buffer + (index * f->item_size),
f->item_size);
tu_fifo_lock(f); // TODO: Here we may distinguish for read and write pointer mutexes!
bool ret = _tu_fifo_peek_at(f, offset, p_buffer, f->wr_idx, f->rd_idx);
tu_fifo_unlock(f);
return true;
return ret;
}
/******************************************************************************/
/*!
@brief Write one element into the RX buffer.
@brief Read n items without removing it from the 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] 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
Number of items to peek
@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)
{
tu_fifo_lock(f); // TODO: Here we may distinguish for read and write pointer mutexes!
bool ret = _tu_fifo_peek_at_n(f, offset, p_buffer, n, f->wr_idx, f->rd_idx);
tu_fifo_unlock(f);
return ret;
}
/******************************************************************************/
/*!
@brief Write one element into the buffer.
This function will write one element into the array index specified by
the write pointer and increment the write index. If the write index
exceeds the max buffer size, then it will roll over to zero.
the write pointer and increment the write index.
@param[in] f
Pointer to the FIFO buffer to manipulate
@ -227,15 +504,23 @@ bool tu_fifo_peek_at(tu_fifo_t* f, uint16_t pos, void * p_buffer)
@returns TRUE if the data was written to the FIFO (overwrittable
FIFO will always return TRUE)
*/
*/
/******************************************************************************/
bool tu_fifo_write (tu_fifo_t* f, const void * data)
bool tu_fifo_write(tu_fifo_t* f, const void * data)
{
if ( tu_fifo_full(f) && !f->overwritable ) return false;
tu_fifo_lock(f);
_ff_push(f, data, 1);
uint16_t w = f->wr_idx;
if ( _tu_fifo_full(f, w, f->rd_idx) && !f->overwritable ) return false;
uint16_t wRel = get_relative_pointer(f, w, 0);
// Write data
_ff_push(f, data, wRel);
// Advance pointer
f->wr_idx = advance_pointer(f, w, 1);
tu_fifo_unlock(f);
@ -245,8 +530,7 @@ bool tu_fifo_write (tu_fifo_t* f, const void * data)
/******************************************************************************/
/*!
@brief This function will write n elements into the array index specified by
the write pointer and increment the write index. If the write index
exceeds the max buffer size, then it will roll over to zero.
the write pointer and increment the write index.
@param[in] f
Pointer to the FIFO buffer to manipulate
@ -255,47 +539,42 @@ bool tu_fifo_write (tu_fifo_t* f, const void * data)
@param[in] count
Number of element
@return Number of written elements
*/
*/
/******************************************************************************/
uint16_t tu_fifo_write_n (tu_fifo_t* f, const void * data, uint16_t count)
uint16_t tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t count)
{
if ( count == 0 ) return 0;
tu_fifo_lock(f);
uint16_t w = f->wr_idx, r = f->rd_idx;
uint8_t const* buf8 = (uint8_t const*) data;
if (!f->overwritable)
{
// Not overwritable limit up to full
count = tu_min16(count, tu_fifo_remaining(f));
count = tu_min16(count, _tu_fifo_remaining(f, w, r));
}
else if (count > f->depth)
{
// Only copy last part
buf8 = buf8 + (count - f->depth) * f->item_size;
count = f->depth;
f->wr_idx = 0;
f->rd_idx = 0;
f->count = 0;
// 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!
f->wr_idx = r;
}
if (count + f->wr_idx <= f->depth )
{
_ff_push(f, buf8, count);
}
else
{
uint16_t const part1 = f->depth - f->wr_idx;
uint16_t wRel = get_relative_pointer(f, w, 0);
// Part 1: from wr_idx to end
_ff_push(f, buf8, part1);
buf8 += part1*f->item_size;
// Write data
_ff_push_n(f, buf8, count, wRel);
// Advance pointer
f->wr_idx = advance_pointer(f, w, count);
// Part 2: start to remaining
_ff_push(f, buf8, count-part1);
}
tu_fifo_unlock(f);
return count;
@ -303,19 +582,59 @@ uint16_t tu_fifo_write_n (tu_fifo_t* f, const void * data, uint16_t count)
/******************************************************************************/
/*!
@brief Clear the fifo read and write pointers and set length to zero
@brief Clear the fifo read and write pointers
@param[in] f
Pointer to the FIFO buffer to manipulate
*/
*/
/******************************************************************************/
bool tu_fifo_clear(tu_fifo_t *f)
{
tu_fifo_lock(f);
f->rd_idx = f->wr_idx = f->count = 0;
f->rd_idx = f->wr_idx = 0;
tu_fifo_unlock(f);
return true;
}
/******************************************************************************/
/*!
@brief Advance 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 forward
*/
/******************************************************************************/
void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n)
{
f->wr_idx = advance_pointer(f, f->wr_idx, n);
}
/******************************************************************************/
/*!
@brief Advance 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 forward
*/
/******************************************************************************/
void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n)
{
f->rd_idx = advance_pointer(f, f->rd_idx, n);
}

View File

@ -31,6 +31,15 @@
#ifndef _TUSB_FIFO_H_
#define _TUSB_FIFO_H_
// Due to the use of unmasked pointers, this FIFO does not suffer from loosing
// one item slice. Furthermore, write and read operations are completely
// decoupled as write and read functions do not modify a common state. Henceforth,
// writing or reading from the FIFO within an ISR is safe as long as no other
// process (thread or ISR) interferes.
// Also, this FIFO is ready to be used in combination with a DMA as the write and
// read pointers can be updated from within a DMA ISR. Overflows are detectable
// within a certain number (see tu_fifo_overflow()).
// mutex is only needed for RTOS
// for OS None, we don't get preempted
#define CFG_FIFO_MUTEX (CFG_TUSB_OS != OPT_OS_NONE)
@ -39,7 +48,7 @@
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
extern "C" {
#endif
#if CFG_FIFO_MUTEX
@ -52,14 +61,16 @@
*/
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 ;
volatile uint16_t count ; ///< number of items in queue
volatile uint16_t wr_idx ; ///< write pointer
volatile uint16_t rd_idx ; ///< read pointer
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
#if CFG_FIFO_MUTEX
tu_fifo_mutex_t mutex;
@ -67,14 +78,16 @@ typedef struct
} tu_fifo_t;
#define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \
uint8_t _name##_buf[_depth*sizeof(_type)]; \
tu_fifo_t _name = { \
.buffer = _name##_buf, \
.depth = _depth, \
.item_size = sizeof(_type), \
.overwritable = _overwritable, \
}
#define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \
uint8_t _name##_buf[_depth*sizeof(_type)]; \
tu_fifo_t _name = { \
.buffer = _name##_buf, \
.depth = _depth, \
.item_size = sizeof(_type), \
.overwritable = _overwritable, \
.max_pointer_idx = 2*_depth-1, \
.non_used_index_space = 0xFFFF - 2*_depth-1, \
}
bool tu_fifo_clear(tu_fifo_t *f);
bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable);
@ -86,46 +99,39 @@ static inline void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t mutex_hdl)
}
#endif
bool tu_fifo_write (tu_fifo_t* f, void const * p_data);
uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * p_data, uint16_t count);
bool tu_fifo_write (tu_fifo_t* f, void const * p_data);
uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * p_data, uint16_t count);
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 count);
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 count);
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_count (tu_fifo_t* f);
bool tu_fifo_empty (tu_fifo_t* f);
bool tu_fifo_full (tu_fifo_t* f);
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);
// 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);
static inline bool tu_fifo_peek(tu_fifo_t* f, void * p_buffer)
{
return tu_fifo_peek_at(f, 0, p_buffer);
}
static inline bool tu_fifo_empty(tu_fifo_t* f)
{
return (f->count == 0);
}
static inline bool tu_fifo_full(tu_fifo_t* f)
{
return (f->count == f->depth);
}
static inline uint16_t tu_fifo_count(tu_fifo_t* f)
{
return f->count;
}
static inline uint16_t tu_fifo_remaining(tu_fifo_t* f)
{
return f->depth - f->count;
}
static inline uint16_t tu_fifo_depth(tu_fifo_t* f)
{
return f->depth;
}
#ifdef __cplusplus
}
}
#endif
#endif /* _TUSB_FIFO_H_ */

View File

@ -37,6 +37,10 @@
#define CFG_TUD_TASK_QUEUE_SZ 16
#endif
#ifndef CFG_TUD_EP_MAX
#define CFG_TUD_EP_MAX 9
#endif
//--------------------------------------------------------------------+
// Device Data
//--------------------------------------------------------------------+
@ -57,7 +61,7 @@ typedef struct
uint8_t speed;
uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid)
uint8_t ep2drv[8][2]; // map endpoint to driver ( 0xff is invalid )
uint8_t ep2drv[CFG_TUD_EP_MAX][2]; // map endpoint to driver ( 0xff is invalid )
struct TU_ATTR_PACKED
{
@ -66,7 +70,7 @@ typedef struct
volatile bool claimed : 1;
// TODO merge ep2drv here, 4-bit should be sufficient
}ep_status[8][2];
}ep_status[CFG_TUD_EP_MAX][2];
}usbd_device_t;
@ -262,7 +266,7 @@ static osal_mutex_t _usbd_mutex;
//--------------------------------------------------------------------+
// Prototypes
//--------------------------------------------------------------------+
static void mark_interface_endpoint(uint8_t ep2drv[8][2], uint8_t const* p_desc, uint16_t desc_len, uint8_t driver_id);
static void mark_interface_endpoint(uint8_t ep2drv[][2], uint8_t const* p_desc, uint16_t desc_len, uint8_t driver_id);
static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request);
static bool process_set_config(uint8_t rhport, uint8_t cfg_num);
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request);
@ -858,7 +862,7 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
}
// Helper marking endpoint of interface belongs to class driver
static void mark_interface_endpoint(uint8_t ep2drv[8][2], uint8_t const* p_desc, uint16_t desc_len, uint8_t driver_id)
static void mark_interface_endpoint(uint8_t ep2drv[][2], uint8_t const* p_desc, uint16_t desc_len, uint8_t driver_id)
{
uint16_t len = 0;

View File

@ -67,7 +67,7 @@ bool tud_suspended(void);
// Check if device is ready to transfer
static inline bool tud_ready(void)
{
return tud_mounted() && !tud_suspended();
return tud_mounted() && !tud_suspended();
}
// Remote wake up host, only if suspended and enabled by host
@ -141,11 +141,11 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
// total length, number of device caps
#define TUD_BOS_DESCRIPTOR(_total_len, _caps_num) \
5, TUSB_DESC_BOS, U16_TO_U8S_LE(_total_len), _caps_num
5, TUSB_DESC_BOS, U16_TO_U8S_LE(_total_len), _caps_num
// Device Capability Platform 128-bit UUID + Data
#define TUD_BOS_PLATFORM_DESCRIPTOR(...) \
4+TU_ARGS_NUM(__VA_ARGS__), TUSB_DESC_DEVICE_CAPABILITY, DEVICE_CAPABILITY_PLATFORM, 0x00, __VA_ARGS__
4+TU_ARGS_NUM(__VA_ARGS__), TUSB_DESC_DEVICE_CAPABILITY, DEVICE_CAPABILITY_PLATFORM, 0x00, __VA_ARGS__
//------------- WebUSB BOS Platform -------------//
@ -154,22 +154,22 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
// Vendor Code, iLandingPage
#define TUD_BOS_WEBUSB_DESCRIPTOR(_vendor_code, _ipage) \
TUD_BOS_PLATFORM_DESCRIPTOR(TUD_BOS_WEBUSB_UUID, U16_TO_U8S_LE(0x0100), _vendor_code, _ipage)
TUD_BOS_PLATFORM_DESCRIPTOR(TUD_BOS_WEBUSB_UUID, U16_TO_U8S_LE(0x0100), _vendor_code, _ipage)
#define TUD_BOS_WEBUSB_UUID \
0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, \
0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65
0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, \
0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65
//------------- Microsoft OS 2.0 Platform -------------//
#define TUD_BOS_MICROSOFT_OS_DESC_LEN 28
// Total Length of descriptor set, vendor code
#define TUD_BOS_MS_OS_20_DESCRIPTOR(_desc_set_len, _vendor_code) \
TUD_BOS_PLATFORM_DESCRIPTOR(TUD_BOS_MS_OS_20_UUID, U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(_desc_set_len), _vendor_code, 0)
TUD_BOS_PLATFORM_DESCRIPTOR(TUD_BOS_MS_OS_20_UUID, U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(_desc_set_len), _vendor_code, 0)
#define TUD_BOS_MS_OS_20_UUID \
0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, \
0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F
0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, \
0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F
//--------------------------------------------------------------------+
// Configuration & Interface Descriptor Templates
@ -180,7 +180,7 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
// Config number, interface count, string index, total length, attribute, power in mA
#define TUD_CONFIG_DESCRIPTOR(config_num, _itfcount, _stridx, _total_len, _attribute, _power_ma) \
9, TUSB_DESC_CONFIGURATION, U16_TO_U8S_LE(_total_len), _itfcount, config_num, _stridx, TU_BIT(7) | _attribute, (_power_ma)/2
9, TUSB_DESC_CONFIGURATION, U16_TO_U8S_LE(_total_len), _itfcount, config_num, _stridx, TU_BIT(7) | _attribute, (_power_ma)/2
//------------- CDC -------------//
@ -190,26 +190,26 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
// CDC Descriptor Template
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
#define TUD_CDC_DESCRIPTOR(_itfnum, _stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize) \
/* Interface Associate */\
8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_NONE, 0,\
/* CDC Control Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_NONE, _stridx,\
/* CDC Header */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\
/* CDC Call */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (uint8_t)((_itfnum) + 1),\
/* CDC ACM: support line request */\
4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 2,\
/* CDC Union */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
/* Endpoint Notification */\
7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 16,\
/* CDC Data Interface */\
9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
/* Endpoint Out */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
/* Interface Associate */\
8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_NONE, 0,\
/* CDC Control Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_NONE, _stridx,\
/* CDC Header */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\
/* CDC Call */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (uint8_t)((_itfnum) + 1),\
/* CDC ACM: support line request */\
4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 2,\
/* CDC Union */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
/* Endpoint Notification */\
7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 16,\
/* CDC Data Interface */\
9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
/* Endpoint Out */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
//------------- MSC -------------//
@ -218,12 +218,12 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
// Interface number, string index, EP Out & EP In address, EP size
#define TUD_MSC_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \
/* Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_MSC, MSC_SUBCLASS_SCSI, MSC_PROTOCOL_BOT, _stridx,\
/* Endpoint Out */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
/* Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_MSC, MSC_SUBCLASS_SCSI, MSC_PROTOCOL_BOT, _stridx,\
/* Endpoint Out */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
//------------- HID -------------//
@ -233,12 +233,12 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
// HID Input only descriptor
// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
#define TUD_HID_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epin, _epsize, _ep_interval) \
/* Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\
/* HID descriptor */\
9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval
/* Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\
/* HID descriptor */\
9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval
// Length of template descriptor: 32 bytes
#define TUD_HID_INOUT_DESC_LEN (9 + 9 + 7 + 7)
@ -246,57 +246,57 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
// HID Input & Output descriptor
// Interface number, string index, protocol, report descriptor len, EP OUT & IN address, size & polling interval
#define TUD_HID_INOUT_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epout, _epin, _epsize, _ep_interval) \
/* Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\
/* HID descriptor */\
9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\
/* Endpoint Out */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval, \
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval
/* Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\
/* HID descriptor */\
9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\
/* Endpoint Out */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval, \
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval
//------------- MIDI -------------//
#define TUD_MIDI_DESC_HEAD_LEN (9 + 9 + 9 + 7)
#define TUD_MIDI_DESC_HEAD(_itfnum, _stridx, _numcables) \
/* Audio Control (AC) Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_FUNC_PROTOCOL_CODE_UNDEF, _stridx,\
/* AC Header */\
9, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(0x0009), 1, (uint8_t)((_itfnum) + 1),\
/* MIDI Streaming (MS) Interface */\
9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum) + 1), 0, 2, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_MIDI_STREAMING, AUDIO_FUNC_PROTOCOL_CODE_UNDEF, 0,\
/* MS Header */\
7, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(7 + (_numcables) * TUD_MIDI_DESC_JACK_LEN)
/* Audio Control (AC) Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_FUNC_PROTOCOL_CODE_UNDEF, _stridx,\
/* AC Header */\
9, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(0x0009), 1, (uint8_t)((_itfnum) + 1),\
/* MIDI Streaming (MS) Interface */\
9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum) + 1), 0, 2, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_MIDI_STREAMING, AUDIO_FUNC_PROTOCOL_CODE_UNDEF, 0,\
/* MS Header */\
7, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(7 + (_numcables) * TUD_MIDI_DESC_JACK_LEN)
#define TUD_MIDI_JACKID_IN_EMB(_cablenum) \
(uint8_t)(((_cablenum) - 1) * 4 + 1)
(uint8_t)(((_cablenum) - 1) * 4 + 1)
#define TUD_MIDI_JACKID_IN_EXT(_cablenum) \
(uint8_t)(((_cablenum) - 1) * 4 + 2)
(uint8_t)(((_cablenum) - 1) * 4 + 2)
#define TUD_MIDI_JACKID_OUT_EMB(_cablenum) \
(uint8_t)(((_cablenum) - 1) * 4 + 3)
(uint8_t)(((_cablenum) - 1) * 4 + 3)
#define TUD_MIDI_JACKID_OUT_EXT(_cablenum) \
(uint8_t)(((_cablenum) - 1) * 4 + 4)
(uint8_t)(((_cablenum) - 1) * 4 + 4)
#define TUD_MIDI_DESC_JACK_LEN (6 + 6 + 9 + 9)
#define TUD_MIDI_DESC_JACK(_cablenum) \
/* MS In Jack (Embedded) */\
6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_IN_EMB(_cablenum), 0,\
/* MS In Jack (External) */\
6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_IN_EXT(_cablenum), 0,\
/* MS Out Jack (Embedded), connected to In Jack External */\
9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_OUT_EMB(_cablenum), 1, TUD_MIDI_JACKID_IN_EXT(_cablenum), 1, 0,\
/* MS Out Jack (External), connected to In Jack Embedded */\
9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_OUT_EXT(_cablenum), 1, TUD_MIDI_JACKID_IN_EMB(_cablenum), 1, 0
/* MS In Jack (Embedded) */\
6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_IN_EMB(_cablenum), 0,\
/* MS In Jack (External) */\
6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_IN_EXT(_cablenum), 0,\
/* MS Out Jack (Embedded), connected to In Jack External */\
9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_OUT_EMB(_cablenum), 1, TUD_MIDI_JACKID_IN_EXT(_cablenum), 1, 0,\
/* MS Out Jack (External), connected to In Jack Embedded */\
9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_OUT_EXT(_cablenum), 1, TUD_MIDI_JACKID_IN_EMB(_cablenum), 1, 0
#define TUD_MIDI_DESC_EP_LEN(_numcables) (7 + 4 + (_numcables))
#define TUD_MIDI_DESC_EP(_epout, _epsize, _numcables) \
/* Endpoint */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
/* MS Endpoint (connected to embedded jack) */\
(uint8_t)(4 + (_numcables)), TUSB_DESC_CS_ENDPOINT, MIDI_CS_ENDPOINT_GENERAL, _numcables
/* Endpoint */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
/* MS Endpoint (connected to embedded jack) */\
(uint8_t)(4 + (_numcables)), TUSB_DESC_CS_ENDPOINT, MIDI_CS_ENDPOINT_GENERAL, _numcables
// Length of template descriptor (88 bytes)
#define TUD_MIDI_DESC_LEN (TUD_MIDI_DESC_HEAD_LEN + TUD_MIDI_DESC_JACK_LEN + TUD_MIDI_DESC_EP_LEN(1) * 2)
@ -305,181 +305,181 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
// - 1 Embedded Jack In connected to 1 External Jack Out
// - 1 Embedded Jack out connected to 1 External Jack In
#define TUD_MIDI_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \
TUD_MIDI_DESC_HEAD(_itfnum, _stridx, 1),\
TUD_MIDI_DESC_JACK(1),\
TUD_MIDI_DESC_EP(_epout, _epsize, 1),\
TUD_MIDI_JACKID_IN_EMB(1),\
TUD_MIDI_DESC_EP(_epin, _epsize, 1),\
TUD_MIDI_JACKID_OUT_EMB(1)
TUD_MIDI_DESC_HEAD(_itfnum, _stridx, 1),\
TUD_MIDI_DESC_JACK(1),\
TUD_MIDI_DESC_EP(_epout, _epsize, 1),\
TUD_MIDI_JACKID_IN_EMB(1),\
TUD_MIDI_DESC_EP(_epin, _epsize, 1),\
TUD_MIDI_JACKID_OUT_EMB(1)
//------------- AUDIO -------------//
/* Standard Interface Association Descriptor (IAD) */
#define TUD_AUDIO_DESC_IAD_LEN 8
#define TUD_AUDIO_DESC_IAD(_firstitfs, _nitfs, _stridx) \
TUD_AUDIO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, _firstitfs, _nitfs, TUSB_CLASS_AUDIO, AUDIO_FUNCTION_SUBCLASS_UNDEFINED, AUDIO_FUNC_PROTOCOL_CODE_V2, _stridx
TUD_AUDIO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, _firstitfs, _nitfs, TUSB_CLASS_AUDIO, AUDIO_FUNCTION_SUBCLASS_UNDEFINED, AUDIO_FUNC_PROTOCOL_CODE_V2, _stridx
/* Standard AC Interface Descriptor(4.7.1) */
#define TUD_AUDIO_DESC_STD_AC_LEN 9
#define TUD_AUDIO_DESC_STD_AC(_itfnum, _nEPs, _stridx) /* _nEPs is 0 or 1 */\
TUD_AUDIO_DESC_STD_AC_LEN, TUSB_DESC_INTERFACE, _itfnum, /* fixed to zero */ 0x00, _nEPs, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_INT_PROTOCOL_CODE_V2, _stridx
TUD_AUDIO_DESC_STD_AC_LEN, TUSB_DESC_INTERFACE, _itfnum, /* fixed to zero */ 0x00, _nEPs, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_INT_PROTOCOL_CODE_V2, _stridx
/* Class-Specific AC Interface Header Descriptor(4.7.2) */
#define TUD_AUDIO_DESC_CS_AC_LEN 9
#define TUD_AUDIO_DESC_CS_AC(_bcdADC, _category, _totallen, _ctrl) /* _bcdADC : Audio Device Class Specification Release Number in Binary-Coded Decimal, _category : see audio_function_t, _totallen : Total number of bytes returned for the class-specific AudioControl interface i.e. Clock Source, Unit and Terminal descriptors - Do not include TUD_AUDIO_DESC_CS_AC_LEN, we already do this here*/ \
TUD_AUDIO_DESC_CS_AC_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_HEADER, U16_TO_U8S_LE(_bcdADC), _category, U16_TO_U8S_LE(_totallen + TUD_AUDIO_DESC_CS_AC_LEN), _ctrl
TUD_AUDIO_DESC_CS_AC_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_HEADER, U16_TO_U8S_LE(_bcdADC), _category, U16_TO_U8S_LE(_totallen + TUD_AUDIO_DESC_CS_AC_LEN), _ctrl
/* Clock Source Descriptor(4.7.2.1) */
#define TUD_AUDIO_DESC_CLK_SRC_LEN 8
#define TUD_AUDIO_DESC_CLK_SRC(_clkid, _attr, _ctrl, _assocTerm, _stridx) \
TUD_AUDIO_DESC_CLK_SRC_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE, _clkid, _attr, _ctrl, _assocTerm, _stridx
TUD_AUDIO_DESC_CLK_SRC_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE, _clkid, _attr, _ctrl, _assocTerm, _stridx
/* Input Terminal Descriptor(4.7.2.4) */
#define TUD_AUDIO_DESC_INPUT_TERM_LEN 17
#define TUD_AUDIO_DESC_INPUT_TERM(_termid, _termtype, _assocTerm, _clkid, _nchannelslogical, _channelcfg, _idxchannelnames, _ctrl, _stridx) \
TUD_AUDIO_DESC_INPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL, _termid, U16_TO_U8S_LE(_termtype), _assocTerm, _clkid, _nchannelslogical, U32_TO_U8S_LE(_channelcfg), _idxchannelnames, U16_TO_U8S_LE(_ctrl), _stridx
TUD_AUDIO_DESC_INPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL, _termid, U16_TO_U8S_LE(_termtype), _assocTerm, _clkid, _nchannelslogical, U32_TO_U8S_LE(_channelcfg), _idxchannelnames, U16_TO_U8S_LE(_ctrl), _stridx
/* Output Terminal Descriptor(4.7.2.5) */
#define TUD_AUDIO_DESC_OUTPUT_TERM_LEN 12
#define TUD_AUDIO_DESC_OUTPUT_TERM(_termid, _termtype, _assocTerm, _srcid, _clkid, _ctrl, _stridx) \
TUD_AUDIO_DESC_OUTPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL, _termid, U16_TO_U8S_LE(_termtype), _assocTerm, _srcid, _clkid, U16_TO_U8S_LE(_ctrl), _stridx
TUD_AUDIO_DESC_OUTPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL, _termid, U16_TO_U8S_LE(_termtype), _assocTerm, _srcid, _clkid, U16_TO_U8S_LE(_ctrl), _stridx
/* Feature Unit Descriptor(4.7.2.8) */
// 1 - Channel
#define TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN 6+(1+1)*4
#define TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(_unitid, _srcid, _ctrlch0master, _ctrlch1, _stridx) \
TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1), _stridx
TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1), _stridx
// For more channels, add definitions here
/* Standard AS Interface Descriptor(4.9.1) */
#define TUD_AUDIO_DESC_STD_AS_INT_LEN 9
#define TUD_AUDIO_DESC_STD_AS_INT(_itfnum, _altset, _nEPs, _stridx) \
TUD_AUDIO_DESC_STD_AS_INT_LEN, TUSB_DESC_INTERFACE, _itfnum, _altset, _nEPs, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_STREAMING, AUDIO_INT_PROTOCOL_CODE_V2, _stridx
TUD_AUDIO_DESC_STD_AS_INT_LEN, TUSB_DESC_INTERFACE, _itfnum, _altset, _nEPs, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_STREAMING, AUDIO_INT_PROTOCOL_CODE_V2, _stridx
/* Class-Specific AS Interface Descriptor(4.9.2) */
#define TUD_AUDIO_DESC_CS_AS_INT_LEN 16
#define TUD_AUDIO_DESC_CS_AS_INT(_termid, _ctrl, _formattype, _formats, _nchannelsphysical, _channelcfg, _stridx) \
TUD_AUDIO_DESC_CS_AS_INT_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AS_INTERFACE_AS_GENERAL, _termid, _ctrl, _formattype, U32_TO_U8S_LE(_formats), _nchannelsphysical, U32_TO_U8S_LE(_channelcfg), _stridx
TUD_AUDIO_DESC_CS_AS_INT_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AS_INTERFACE_AS_GENERAL, _termid, _ctrl, _formattype, U32_TO_U8S_LE(_formats), _nchannelsphysical, U32_TO_U8S_LE(_channelcfg), _stridx
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */
#define TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN 6
#define TUD_AUDIO_DESC_TYPE_I_FORMAT(_subslotsize, _bitresolution) /* _subslotsize is number of bytes per sample (i.e. subslot) and can be 1,2,3, or 4 */\
TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AS_INTERFACE_FORMAT_TYPE, AUDIO_FORMAT_TYPE_I, _subslotsize, _bitresolution
TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AS_INTERFACE_FORMAT_TYPE, AUDIO_FORMAT_TYPE_I, _subslotsize, _bitresolution
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */
#define TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN 7
#define TUD_AUDIO_DESC_STD_AS_ISO_EP(_ep, _attr, _maxEPsize, _interval) \
TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN, TUSB_DESC_ENDPOINT, _ep, _attr, U16_TO_U8S_LE(_maxEPsize), _interval
TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN, TUSB_DESC_ENDPOINT, _ep, _attr, U16_TO_U8S_LE(_maxEPsize), _interval
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */
#define TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN 8
#define TUD_AUDIO_DESC_CS_AS_ISO_EP(_attr, _ctrl, _lockdelayunit, _lockdelay) \
TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN, TUSB_DESC_CS_ENDPOINT, AUDIO_CS_EP_SUBTYPE_GENERAL, _attr, _ctrl, _lockdelayunit, U16_TO_U8S_LE(_lockdelay)
TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN, TUSB_DESC_CS_ENDPOINT, AUDIO_CS_EP_SUBTYPE_GENERAL, _attr, _ctrl, _lockdelayunit, U16_TO_U8S_LE(_lockdelay)
/* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */
#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN 7
#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_ep, _interval) \
TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_NO_SYNC | TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval
TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_NO_SYNC | TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval
// AUDIO simple descriptor (UAC2) for 1 microphone input
// - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source
#define TUD_AUDIO_MIC_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\
+ TUD_AUDIO_DESC_STD_AC_LEN\
+ TUD_AUDIO_DESC_CS_AC_LEN\
+ TUD_AUDIO_DESC_CLK_SRC_LEN\
+ TUD_AUDIO_DESC_INPUT_TERM_LEN\
+ TUD_AUDIO_DESC_OUTPUT_TERM_LEN\
+ TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN\
+ TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ TUD_AUDIO_DESC_CS_AS_INT_LEN\
+ TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+ TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN)
+ TUD_AUDIO_DESC_STD_AC_LEN\
+ TUD_AUDIO_DESC_CS_AC_LEN\
+ TUD_AUDIO_DESC_CLK_SRC_LEN\
+ TUD_AUDIO_DESC_INPUT_TERM_LEN\
+ TUD_AUDIO_DESC_OUTPUT_TERM_LEN\
+ TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN\
+ TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ TUD_AUDIO_DESC_CS_AS_INT_LEN\
+ TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+ TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN)
#define TUD_AUDIO_MIC_DESC_N_AS_INT 1 // Number of AS interfaces
#define TUD_AUDIO_MIC_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \
/* Standard Interface Association Descriptor (IAD) */\
TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
/* Standard AC Interface Descriptor(4.7.1) */\
TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
/* Class-Specific AC Interface Header Descriptor(4.7.2) */\
TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\
/* Clock Source Descriptor(4.7.2.1) */\
TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\
/* Input Terminal Descriptor(4.7.2.4) */\
TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x03, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00),\
/* Output Terminal Descriptor(4.7.2.5) */\
TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\
/* Feature Unit Descriptor(4.7.2.8) */\
TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\
/* Standard AS Interface Descriptor(4.9.1) */\
/* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\
TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\
/* Standard AS Interface Descriptor(4.9.1) */\
/* Interface 1, Alternate 1 - alternate interface for data streaming */\
TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\
/* Class-Specific AS Interface Descriptor(4.9.2) */\
TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x03, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000)
/* Standard Interface Association Descriptor (IAD) */\
TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
/* Standard AC Interface Descriptor(4.7.1) */\
TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
/* Class-Specific AC Interface Header Descriptor(4.7.2) */\
TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\
/* Clock Source Descriptor(4.7.2.1) */\
TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\
/* Input Terminal Descriptor(4.7.2.4) */\
TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x03, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00),\
/* Output Terminal Descriptor(4.7.2.5) */\
TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\
/* Feature Unit Descriptor(4.7.2.8) */\
TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\
/* Standard AS Interface Descriptor(4.9.1) */\
/* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\
TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\
/* Standard AS Interface Descriptor(4.9.1) */\
/* Interface 1, Alternate 1 - alternate interface for data streaming */\
TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\
/* Class-Specific AS Interface Descriptor(4.9.2) */\
TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x03, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000)
// AUDIO simple descriptor (UAC2) for mono speaker
// - 1 Input Terminal, 2 Feature Unit (Mute and Volume Control), 3 Output Terminal, 4 Clock Source
#define TUD_AUDIO_SPEAKER_MONO_FB_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\
+ TUD_AUDIO_DESC_STD_AC_LEN\
+ TUD_AUDIO_DESC_CS_AC_LEN\
+ TUD_AUDIO_DESC_CLK_SRC_LEN\
+ TUD_AUDIO_DESC_INPUT_TERM_LEN\
+ TUD_AUDIO_DESC_OUTPUT_TERM_LEN\
+ TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN\
+ TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ TUD_AUDIO_DESC_CS_AS_INT_LEN\
+ TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+ TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\
+ TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN)
+ TUD_AUDIO_DESC_STD_AC_LEN\
+ TUD_AUDIO_DESC_CS_AC_LEN\
+ TUD_AUDIO_DESC_CLK_SRC_LEN\
+ TUD_AUDIO_DESC_INPUT_TERM_LEN\
+ TUD_AUDIO_DESC_OUTPUT_TERM_LEN\
+ TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN\
+ TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ TUD_AUDIO_DESC_STD_AS_INT_LEN\
+ TUD_AUDIO_DESC_CS_AS_INT_LEN\
+ TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+ TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+ TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\
+ TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN)
#define TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize, _epfb) \
/* Standard Interface Association Descriptor (IAD) */\
TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
/* Standard AC Interface Descriptor(4.7.1) */\
TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
/* Class-Specific AC Interface Header Descriptor(4.7.2) */\
TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\
/* Clock Source Descriptor(4.7.2.1) */\
TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\
/* Input Terminal Descriptor(4.7.2.4) */\
TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\
/* Output Terminal Descriptor(4.7.2.5) */\
TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\
/* Feature Unit Descriptor(4.7.2.8) */\
TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ 0 * (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch1*/ 0 * (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_stridx*/ 0x00),\
/* Standard AS Interface Descriptor(4.9.1) */\
/* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\
TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\
/* Standard AS Interface Descriptor(4.9.1) */\
/* Interface 1, Alternate 1 - alternate interface for data streaming */\
TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x02, /*_stridx*/ 0x00),\
/* Class-Specific AS Interface Descriptor(4.9.2) */\
TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\
/* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\
TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_interval*/ 1)\
/* Standard Interface Association Descriptor (IAD) */\
TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
/* Standard AC Interface Descriptor(4.7.1) */\
TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
/* Class-Specific AC Interface Header Descriptor(4.7.2) */\
TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\
/* Clock Source Descriptor(4.7.2.1) */\
TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\
/* Input Terminal Descriptor(4.7.2.4) */\
TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\
/* Output Terminal Descriptor(4.7.2.5) */\
TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\
/* Feature Unit Descriptor(4.7.2.8) */\
TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ 0 * (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch1*/ 0 * (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_stridx*/ 0x00),\
/* Standard AS Interface Descriptor(4.9.1) */\
/* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\
TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\
/* Standard AS Interface Descriptor(4.9.1) */\
/* Interface 1, Alternate 1 - alternate interface for data streaming */\
TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x02, /*_stridx*/ 0x00),\
/* Class-Specific AS Interface Descriptor(4.9.2) */\
TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\
/* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\
TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_interval*/ 1)\
//------------- TUD_USBTMC/USB488 -------------//
#define TUD_USBTMC_APP_CLASS (TUSB_CLASS_APPLICATION_SPECIFIC)
@ -491,23 +491,23 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
// Interface number, number of endpoints, EP string index, USB_TMC_PROTOCOL*, bulk-out endpoint ID,
// bulk-in endpoint ID
#define TUD_USBTMC_IF_DESCRIPTOR(_itfnum, _bNumEndpoints, _stridx, _itfProtocol) \
/* Interface */ \
0x09, TUSB_DESC_INTERFACE, _itfnum, 0x00, _bNumEndpoints, TUD_USBTMC_APP_CLASS, TUD_USBTMC_APP_SUBCLASS, _itfProtocol, _stridx
/* Interface */ \
0x09, TUSB_DESC_INTERFACE, _itfnum, 0x00, _bNumEndpoints, TUD_USBTMC_APP_CLASS, TUD_USBTMC_APP_SUBCLASS, _itfProtocol, _stridx
#define TUD_USBTMC_IF_DESCRIPTOR_LEN 9u
#define TUD_USBTMC_BULK_DESCRIPTORS(_epout, _epin, _bulk_epsize) \
/* Endpoint Out */ \
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u, \
/* Endpoint In */ \
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u
/* Endpoint Out */ \
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u, \
/* Endpoint In */ \
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_bulk_epsize), 0u
#define TUD_USBTMC_BULK_DESCRIPTORS_LEN (7u+7u)
/* optional interrupt endpoint */ \
// _int_pollingInterval : for LS/FS, expressed in frames (1ms each). 16 may be a good number?
#define TUD_USBTMC_INT_DESCRIPTOR(_ep_interrupt, _ep_interrupt_size, _int_pollingInterval ) \
7, TUSB_DESC_ENDPOINT, _ep_interrupt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_interrupt_size), 0x16
7, TUSB_DESC_ENDPOINT, _ep_interrupt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_interrupt_size), 0x16
#define TUD_USBTMC_INT_DESCRIPTOR_LEN (7u)
@ -517,12 +517,12 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
// Interface number, string index, EP Out & IN address, EP size
#define TUD_VENDOR_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \
/* Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_VENDOR_SPECIFIC, 0x00, 0x00, _stridx,\
/* Endpoint Out */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
/* Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_VENDOR_SPECIFIC, 0x00, 0x00, _stridx,\
/* Endpoint Out */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
//------------- DFU Runtime -------------//
#define TUD_DFU_APP_CLASS (TUSB_CLASS_APPLICATION_SPECIFIC)
@ -534,10 +534,10 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
// DFU runtime descriptor
// Interface number, string index, attributes, detach timeout, transfer size
#define TUD_DFU_RT_DESCRIPTOR(_itfnum, _stridx, _attr, _timeout, _xfer_size) \
/* Interface */ \
9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUD_DFU_APP_CLASS, TUD_DFU_APP_SUBCLASS, DFU_PROTOCOL_RT, _stridx, \
/* Function */ \
9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0101)
/* Interface */ \
9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUD_DFU_APP_CLASS, TUD_DFU_APP_SUBCLASS, DFU_PROTOCOL_RT, _stridx, \
/* Function */ \
9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0101)
//------------- CDC-ECM -------------//
@ -548,26 +548,26 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
// CDC-ECM Descriptor Template
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
#define TUD_CDC_ECM_DESCRIPTOR(_itfnum, _desc_stridx, _mac_stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize, _maxsegmentsize) \
/* Interface Association */\
8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 0, 0,\
/* CDC Control Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 0, _desc_stridx,\
/* CDC-ECM Header */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\
/* CDC-ECM Union */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
/* CDC-ECM Functional Descriptor */\
13, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ETHERNET_NETWORKING, _mac_stridx, 0, 0, 0, 0, U16_TO_U8S_LE(_maxsegmentsize), U16_TO_U8S_LE(0), 0,\
/* Endpoint Notification */\
7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 1,\
/* CDC Data Interface (default inactive) */\
9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 0, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
/* CDC Data Interface (alternative active) */\
9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 1, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
/* Endpoint Out */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
/* Interface Association */\
8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 0, 0,\
/* CDC Control Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 0, _desc_stridx,\
/* CDC-ECM Header */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\
/* CDC-ECM Union */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
/* CDC-ECM Functional Descriptor */\
13, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ETHERNET_NETWORKING, _mac_stridx, 0, 0, 0, 0, U16_TO_U8S_LE(_maxsegmentsize), U16_TO_U8S_LE(0), 0,\
/* Endpoint Notification */\
7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 1,\
/* CDC Data Interface (default inactive) */\
9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 0, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
/* CDC Data Interface (alternative active) */\
9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 1, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
/* Endpoint Out */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
//------------- RNDIS -------------//
@ -590,26 +590,26 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
// RNDIS Descriptor Template
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
#define TUD_RNDIS_DESCRIPTOR(_itfnum, _stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize) \
/* Interface Association */\
8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUD_RNDIS_ITF_CLASS, TUD_RNDIS_ITF_SUBCLASS, TUD_RNDIS_ITF_PROTOCOL, 0,\
/* CDC Control Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUD_RNDIS_ITF_CLASS, TUD_RNDIS_ITF_SUBCLASS, TUD_RNDIS_ITF_PROTOCOL, _stridx,\
/* CDC-ACM Header */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0110),\
/* CDC Call Management */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (uint8_t)((_itfnum) + 1),\
/* ACM */\
4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 0,\
/* CDC Union */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
/* Endpoint Notification */\
7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 1,\
/* CDC Data Interface */\
9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
/* Endpoint Out */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
/* Interface Association */\
8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUD_RNDIS_ITF_CLASS, TUD_RNDIS_ITF_SUBCLASS, TUD_RNDIS_ITF_PROTOCOL, 0,\
/* CDC Control Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUD_RNDIS_ITF_CLASS, TUD_RNDIS_ITF_SUBCLASS, TUD_RNDIS_ITF_PROTOCOL, _stridx,\
/* CDC-ACM Header */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0110),\
/* CDC Call Management */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (uint8_t)((_itfnum) + 1),\
/* ACM */\
4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 0,\
/* CDC Union */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
/* Endpoint Notification */\
7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 1,\
/* CDC Data Interface */\
9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
/* Endpoint Out */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
//------------- BT Radio -------------//
#define TUD_BT_APP_CLASS (TUSB_CLASS_WIRELESS_CONTROLLER)
@ -626,20 +626,20 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
/* Primary Interface */
#define TUD_BTH_PRI_ITF(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size) \
9, TUSB_DESC_INTERFACE, _itfnum, _stridx, 3, TUD_BT_APP_CLASS, TUD_BT_APP_SUBCLASS, TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, 0, \
/* Endpoint In for events */ \
7, TUSB_DESC_ENDPOINT, _ep_evt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_evt_size), _ep_evt_interval, \
/* Endpoint In for ACL data */ \
7, TUSB_DESC_ENDPOINT, _ep_in, TUSB_XFER_BULK, U16_TO_U8S_LE(_ep_size), 1, \
/* Endpoint Out for ACL data */ \
7, TUSB_DESC_ENDPOINT, _ep_out, TUSB_XFER_BULK, U16_TO_U8S_LE(_ep_size), 1
9, TUSB_DESC_INTERFACE, _itfnum, _stridx, 3, TUD_BT_APP_CLASS, TUD_BT_APP_SUBCLASS, TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, 0, \
/* Endpoint In for events */ \
7, TUSB_DESC_ENDPOINT, _ep_evt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_evt_size), _ep_evt_interval, \
/* Endpoint In for ACL data */ \
7, TUSB_DESC_ENDPOINT, _ep_in, TUSB_XFER_BULK, U16_TO_U8S_LE(_ep_size), 1, \
/* Endpoint Out for ACL data */ \
7, TUSB_DESC_ENDPOINT, _ep_out, TUSB_XFER_BULK, U16_TO_U8S_LE(_ep_size), 1
#define TUD_BTH_ISO_ITF(_itfnum, _alt, _ep_in, _ep_out, _n) ,\
/* Interface with 2 endpoints */ \
9, TUSB_DESC_INTERFACE, _itfnum, _alt, 2, TUD_BT_APP_CLASS, TUD_BT_APP_SUBCLASS, TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, 0, \
/* Isochronous endpoints */ \
7, TUSB_DESC_ENDPOINT, _ep_in, TUSB_XFER_ISOCHRONOUS, U16_TO_U8S_LE(_n), 1, \
7, TUSB_DESC_ENDPOINT, _ep_out, TUSB_XFER_ISOCHRONOUS, U16_TO_U8S_LE(_n), 1
/* Interface with 2 endpoints */ \
9, TUSB_DESC_INTERFACE, _itfnum, _alt, 2, TUD_BT_APP_CLASS, TUD_BT_APP_SUBCLASS, TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, 0, \
/* Isochronous endpoints */ \
7, TUSB_DESC_ENDPOINT, _ep_in, TUSB_XFER_ISOCHRONOUS, U16_TO_U8S_LE(_n), 1, \
7, TUSB_DESC_ENDPOINT, _ep_out, TUSB_XFER_ISOCHRONOUS, U16_TO_U8S_LE(_n), 1
#define _FIRST(a, ...) a
#define _REST(a, ...) __VA_ARGS__
@ -647,24 +647,24 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
#define TUD_BTH_ISO_ITF_0(_itfnum, ...)
#define TUD_BTH_ISO_ITF_1(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 1, _ep_in, _ep_out, _FIRST(__VA_ARGS__))
#define TUD_BTH_ISO_ITF_2(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 2, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \
TUD_BTH_ISO_ITF_1(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__))
TUD_BTH_ISO_ITF_1(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__))
#define TUD_BTH_ISO_ITF_3(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 3, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \
TUD_BTH_ISO_ITF_2(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__))
TUD_BTH_ISO_ITF_2(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__))
#define TUD_BTH_ISO_ITF_4(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 4, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \
TUD_BTH_ISO_ITF_3(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__))
TUD_BTH_ISO_ITF_3(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__))
#define TUD_BTH_ISO_ITF_5(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 5, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \
TUD_BTH_ISO_ITF_4(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__))
TUD_BTH_ISO_ITF_4(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__))
#define TUD_BTH_ISO_ITF_6(_itfnum, _ep_in, _ep_out, ...) TUD_BTH_ISO_ITF(_itfnum, (CFG_TUD_BTH_ISO_ALT_COUNT) - 6, _ep_in, _ep_out, _FIRST(__VA_ARGS__)) \
TUD_BTH_ISO_ITF_5(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__))
TUD_BTH_ISO_ITF_5(_itfnum, _ep_in, _ep_out, _REST(__VA_ARGS__))
#define TUD_BTH_ISO_ITFS(_itfnum, _ep_in, _ep_out, ...) \
TU_XSTRCAT(TUD_BTH_ISO_ITF_, CFG_TUD_BTH_ISO_ALT_COUNT)(_itfnum, _ep_in, _ep_out, __VA_ARGS__)
TU_XSTRCAT(TUD_BTH_ISO_ITF_, CFG_TUD_BTH_ISO_ALT_COUNT)(_itfnum, _ep_in, _ep_out, __VA_ARGS__)
// BT Primary controller descriptor
// Interface number, string index, attributes, event endpoint, event endpoint size, interval, data in, data out, data endpoint size, iso endpoint sizes
#define TUD_BTH_DESCRIPTOR(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size,...) \
TUD_BTH_PRI_ITF(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size) \
TUD_BTH_ISO_ITFS(_itfnum + 1, _ep_in + 1, _ep_out + 1, __VA_ARGS__)
TUD_BTH_PRI_ITF(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size) \
TUD_BTH_ISO_ITFS(_itfnum + 1, _ep_in + 1, _ep_out + 1, __VA_ARGS__)
#ifdef __cplusplus
}

View File

@ -53,6 +53,9 @@ enum
enum
{
// Endpoint number is fixed (8) for ISOOUT and ISOIN.
EP_ISO_NUM = 8,
// CBI endpoints count
EP_COUNT = 8
};
@ -62,11 +65,14 @@ typedef struct
uint8_t* buffer;
uint16_t total_len;
volatile uint16_t actual_len;
uint8_t mps; // max packet size
uint16_t mps; // max packet size
// nrf52840 will auto ACK OUT packet after DMA is done
// indicate packet is already ACK
volatile bool data_received;
// Set to true when data was transferred from RAM to ISO IN output buffer.
// New data can be put in ISO IN output buffer after SOF.
bool iso_in_transfer_ready;
} xfer_td_t;
@ -74,7 +80,8 @@ typedef struct
static struct
{
// All 8 endpoints including control IN & OUT (offset 1)
xfer_td_t xfer[EP_COUNT][2];
// +1 for ISO endpoints
xfer_td_t xfer[EP_COUNT + 1][2];
// Number of pending DMA that is started but not handled yet by dcd_int_handler().
// Since nRF can only carry one DMA can run at a time, this value is normally be either 0 or 1.
@ -173,6 +180,7 @@ static void xact_out_prepare(uint8_t epnum)
{
// Write zero value to SIZE register will allow hw to ACK (accept data)
// If it is not already done by DMA
// SIZE.ISOOUT can also be accessed this way
NRF_USBD->SIZE.EPOUT[epnum] = 0;
}
@ -183,15 +191,32 @@ static void xact_out_prepare(uint8_t epnum)
static void xact_out_dma(uint8_t epnum)
{
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
uint32_t xact_len;
uint8_t const xact_len = NRF_USBD->SIZE.EPOUT[epnum];
if (epnum == EP_ISO_NUM)
{
xact_len = NRF_USBD->SIZE.ISOOUT;
// If ZERO bit is set, ignore ISOOUT length
if (xact_len & USBD_SIZE_ISOOUT_ZERO_Msk) xact_len = 0;
else
{
// Trigger DMA move data from Endpoint -> SRAM
NRF_USBD->ISOOUT.PTR = (uint32_t) xfer->buffer;
NRF_USBD->ISOOUT.MAXCNT = xact_len;
// Trigger DMA move data from Endpoint -> SRAM
NRF_USBD->EPOUT[epnum].PTR = (uint32_t) xfer->buffer;
NRF_USBD->EPOUT[epnum].MAXCNT = xact_len;
edpt_dma_start(&NRF_USBD->TASKS_STARTISOOUT);
}
}
else
{
xact_len = (uint8_t)NRF_USBD->SIZE.EPOUT[epnum];
edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[epnum]);
// Trigger DMA move data from Endpoint -> SRAM
NRF_USBD->EPOUT[epnum].PTR = (uint32_t) xfer->buffer;
NRF_USBD->EPOUT[epnum].MAXCNT = xact_len;
edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[epnum]);
}
xfer->buffer += xact_len;
xfer->actual_len += xact_len;
}
@ -205,7 +230,7 @@ static void xact_in_prepare(uint8_t epnum)
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN);
// Each transaction is up to Max Packet Size
uint8_t const xact_len = tu_min16(xfer->total_len - xfer->actual_len, xfer->mps);
uint16_t const xact_len = tu_min16(xfer->total_len - xfer->actual_len, xfer->mps);
NRF_USBD->EPIN[epnum].PTR = (uint32_t) xfer->buffer;
NRF_USBD->EPIN[epnum].MAXCNT = xact_len;
@ -296,20 +321,94 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
_dcd.xfer[epnum][dir].mps = desc_edpt->wMaxPacketSize.size;
if ( dir == TUSB_DIR_OUT )
if (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS)
{
NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + epnum);
NRF_USBD->EPOUTEN |= TU_BIT(epnum);
}else
if (dir == TUSB_DIR_OUT)
{
NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + epnum);
NRF_USBD->EPOUTEN |= TU_BIT(epnum);
}else
{
NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPIN0_Pos + epnum);
NRF_USBD->EPINEN |= TU_BIT(epnum);
}
}
else
{
NRF_USBD->INTENSET = TU_BIT(USBD_INTEN_ENDEPIN0_Pos + epnum);
NRF_USBD->EPINEN |= TU_BIT(epnum);
TU_ASSERT(epnum == EP_ISO_NUM);
if (dir == TUSB_DIR_OUT)
{
// SPLIT ISO buffer when ISO IN endpoint is already opened.
if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_IN].mps) NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN;
// Clear old events
NRF_USBD->EVENTS_ENDISOOUT = 0;
// Clear SOF event in case interrupt was not enabled yet.
if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0;
// Enable SOF and ISOOUT interrupts, and ISOOUT endpoint.
NRF_USBD->INTENSET = USBD_INTENSET_ENDISOOUT_Msk | USBD_INTENSET_SOF_Msk;
NRF_USBD->EPOUTEN |= USBD_EPOUTEN_ISOOUT_Msk;
}
else
{
NRF_USBD->EVENTS_ENDISOIN = 0;
// SPLIT ISO buffer when ISO OUT endpoint is already opened.
if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_OUT].mps) NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_HalfIN;
// Clear SOF event in case interrupt was not enabled yet.
if ((NRF_USBD->INTEN & USBD_INTEN_SOF_Msk) == 0) NRF_USBD->EVENTS_SOF = 0;
// Enable SOF and ISOIN interrupts, and ISOIN endpoint.
NRF_USBD->INTENSET = USBD_INTENSET_ENDISOIN_Msk | USBD_INTENSET_SOF_Msk;
NRF_USBD->EPINEN |= USBD_EPINEN_ISOIN_Msk;
}
}
__ISB(); __DSB();
return true;
}
void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
if (epnum != EP_ISO_NUM)
{
// CBI
if (dir == TUSB_DIR_OUT)
{
NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPOUT0_Pos + epnum);
NRF_USBD->EPOUTEN &= ~TU_BIT(epnum);
}
else
{
NRF_USBD->INTENCLR = TU_BIT(USBD_INTEN_ENDEPIN0_Pos + epnum);
NRF_USBD->EPINEN &= ~TU_BIT(epnum);
}
}
else
{
_dcd.xfer[EP_ISO_NUM][dir].mps = 0;
// ISO
if (dir == TUSB_DIR_OUT)
{
NRF_USBD->INTENCLR = USBD_INTENCLR_ENDISOOUT_Msk;
NRF_USBD->EPOUTEN &= ~USBD_EPOUTEN_ISOOUT_Msk;
NRF_USBD->EVENTS_ENDISOOUT = 0;
}
else
{
NRF_USBD->INTENCLR = USBD_INTENCLR_ENDISOIN_Msk;
NRF_USBD->EPINEN &= ~USBD_EPINEN_ISOIN_Msk;
}
// One of the ISO endpoints closed, no need to split buffers any more.
NRF_USBD->ISOSPLIT = USBD_ISOSPLIT_SPLIT_OneDir;
// When both ISO endpoint are close there is no need for SOF any more.
if (_dcd.xfer[EP_ISO_NUM][TUSB_DIR_IN].mps + _dcd.xfer[EP_ISO_NUM][TUSB_DIR_OUT].mps == 0) NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk;
}
__ISB(); __DSB();
}
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
(void) rhport;
@ -361,11 +460,12 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
if ( tu_edpt_number(ep_addr) == 0 )
if ( epnum == 0 )
{
NRF_USBD->TASKS_EP0STALL = 1;
}else
}else if (epnum != EP_ISO_NUM)
{
NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_Stall << USBD_EPSTALL_STALL_Pos) | ep_addr;
}
@ -376,8 +476,9 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
if ( tu_edpt_number(ep_addr) )
if ( epnum != 0 && epnum != EP_ISO_NUM )
{
// clear stall
NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
@ -435,8 +536,31 @@ void dcd_int_handler(uint8_t rhport)
dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
}
// ISOIN: Data was moved to endpoint buffer, client will be notified in SOF
if ( int_status & USBD_INTEN_ENDISOIN_Msk )
{
xfer_td_t* xfer = get_td(EP_ISO_NUM, TUSB_DIR_IN);
xfer->actual_len = NRF_USBD->ISOIN.AMOUNT;
// Data transferred from RAM to endpoint output buffer.
// Next transfer can be scheduled after SOF.
xfer->iso_in_transfer_ready = true;
}
if ( int_status & USBD_INTEN_SOF_Msk )
{
// ISOOUT: Transfer data gathered in previous frame from buffer to RAM
if (NRF_USBD->EPOUTEN & USBD_EPOUTEN_ISOOUT_Msk)
{
xact_out_dma(EP_ISO_NUM);
}
// ISOIN: Notify client that data was transferred
xfer_td_t* xfer = get_td(EP_ISO_NUM, TUSB_DIR_IN);
if ( xfer->iso_in_transfer_ready )
{
xfer->iso_in_transfer_ready = false;
dcd_event_xfer_complete(0, EP_ISO_NUM | TUSB_DIR_IN_MASK, xfer->actual_len, XFER_RESULT_SUCCESS, true);
}
dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
}
@ -518,8 +642,11 @@ void dcd_int_handler(uint8_t rhport)
* Note: Since nRF controller auto ACK next packet without SW awareness
* We must handle this stage before Host -> Endpoint just in case
* 2 event happens at once
* ISO OUT: Transaction must fit in single packed, it can be shorter then total
* len if Host decides to sent fewer bytes, it this case transaction is also
* complete and next transfer is not initiated here like for CBI.
*/
for(uint8_t epnum=0; epnum<8; epnum++)
for(uint8_t epnum=0; epnum<EP_COUNT+1; epnum++)
{
if ( tu_bit_test(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum))
{
@ -530,7 +657,7 @@ void dcd_int_handler(uint8_t rhport)
xfer->data_received = false;
// Transfer complete if transaction len < Max Packet Size or total len is transferred
if ( (xact_len == xfer->mps) && (xfer->actual_len < xfer->total_len) )
if ( (epnum != EP_ISO_NUM) && (xact_len == xfer->mps) && (xfer->actual_len < xfer->total_len) )
{
// Prepare for next transaction
xact_out_prepare(epnum);