Merge branch 'master' of https://github.com/hathach/tinyusb into rx_fb

This commit is contained in:
HiFiPhile
2024-07-28 11:59:52 +02:00
160 changed files with 4439 additions and 2919 deletions

View File

@@ -489,7 +489,7 @@ typedef enum
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 = 0x80000000,
AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA = 0x80000000u,
} audio_data_format_type_I_t;
/// All remaining definitions are taken from the descriptor descriptions in the UAC2 main specification
@@ -640,7 +640,7 @@ typedef enum
AUDIO_CHANNEL_CONFIG_BOTTOM_CENTER = 0x01000000,
AUDIO_CHANNEL_CONFIG_BACK_LEFT_OF_CENTER = 0x02000000,
AUDIO_CHANNEL_CONFIG_BACK_RIGHT_OF_CENTER = 0x04000000,
AUDIO_CHANNEL_CONFIG_RAW_DATA = 0x80000000,
AUDIO_CHANNEL_CONFIG_RAW_DATA = 0x80000000u,
} audio_channel_config_t;
/// AUDIO Channel Cluster Descriptor (4.1)

View File

@@ -307,19 +307,6 @@ typedef struct
uint16_t desc_length; // Length of audio function descriptor
// Buffer for control requests
uint8_t * ctrl_buf;
uint8_t ctrl_buf_sz;
// Current active alternate settings
uint8_t * alt_setting; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP!
// EP Transfer buffers and FIFOs
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
#if !CFG_TUD_AUDIO_ENABLE_DECODING
tu_fifo_t ep_out_ff;
#endif
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
struct {
CFG_TUSB_MEM_ALIGN uint32_t send_buf;
@@ -350,17 +337,6 @@ typedef struct
} feedback;
#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
tu_fifo_t ep_in_ff;
#endif
// Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74)
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[6];
#endif
// Decoding parameters - parameters are set when alternate AS interface is set by host
// Coding is currently only supported for EP. Software coding corresponding to AS interfaces without EPs are not supported currently.
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
@@ -369,8 +345,7 @@ typedef struct
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
audio_data_format_type_I_t format_type_I_rx;
uint8_t n_bytes_per_sampe_rx;
uint8_t n_channels_per_ff_rx;
uint8_t n_bytes_per_sample_rx;
uint8_t n_ff_used_rx;
#endif
#endif
@@ -386,26 +361,57 @@ typedef struct
#if CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL)
audio_format_type_t format_type_tx;
uint8_t n_channels_tx;
uint8_t n_bytes_per_sampe_tx;
uint8_t n_bytes_per_sample_tx;
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
audio_data_format_type_I_t format_type_I_tx;
uint8_t n_channels_per_ff_tx;
uint8_t n_ff_used_tx;
#endif
#endif
// Buffer for control requests
uint8_t * ctrl_buf;
uint8_t ctrl_buf_sz;
// Current active alternate settings
uint8_t * alt_setting; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP!
// EP Transfer buffers and FIFOs
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
#if !CFG_TUD_AUDIO_ENABLE_DECODING
tu_fifo_t ep_out_ff;
#endif
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
tu_fifo_t ep_in_ff;
#endif
// Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74)
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[6];
#endif
// Support FIFOs for software encoding and decoding
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
tu_fifo_t * rx_supp_ff;
uint8_t n_rx_supp_ff;
uint16_t rx_supp_ff_sz_max;
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
uint8_t n_channels_per_ff_rx;
#endif
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
tu_fifo_t * tx_supp_ff;
uint8_t n_tx_supp_ff;
uint16_t tx_supp_ff_sz_max;
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
uint8_t n_channels_per_ff_tx;
#endif
#endif
// Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR the support FIFOs are used
@@ -847,16 +853,16 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, u
if (info.len_lin != 0)
{
info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin);
src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx];
src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sample_rx];
dst_end = info.ptr_lin + info.len_lin;
src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_lin, dst_end, src, n_ff_used);
src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sample_rx, info.ptr_lin, dst_end, src, n_ff_used);
// Handle wrapped part of FIFO
info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap);
if (info.len_wrap != 0)
{
dst_end = info.ptr_wrap + info.len_wrap;
audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_wrap, dst_end, src, n_ff_used);
audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sample_rx, info.ptr_wrap, dst_end, src, n_ff_used);
}
tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
}
@@ -1171,7 +1177,7 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
// Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT!
nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, audio->ep_in_sz / n_ff_used);
// Round to full number of samples (flooring)
uint16_t const nSlotSize = audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx;
uint16_t const nSlotSize = audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx;
nBytesPerFFToSend = (nBytesPerFFToSend / nSlotSize) * nSlotSize;
#endif
@@ -1183,7 +1189,7 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++)
{
dst = &audio->lin_buf_in[cnt_ff*audio->n_channels_per_ff_tx*audio->n_bytes_per_sampe_tx];
dst = &audio->lin_buf_in[cnt_ff*audio->n_channels_per_ff_tx*audio->n_bytes_per_sample_tx];
tu_fifo_get_read_info(&audio->tx_supp_ff[cnt_ff], &info);
@@ -1191,7 +1197,7 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
{
info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin); // Limit up to desired length
src_end = (uint8_t *)info.ptr_lin + info.len_lin;
dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_lin, src_end, dst, n_ff_used);
dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sample_tx, info.ptr_lin, src_end, dst, n_ff_used);
// Limit up to desired length
info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap);
@@ -1200,7 +1206,7 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
if (info.len_wrap != 0)
{
src_end = (uint8_t *)info.ptr_wrap + info.len_wrap;
audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_wrap, src_end, dst, n_ff_used);
audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sample_tx, info.ptr_wrap, src_end, dst, n_ff_used);
}
tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
@@ -1666,7 +1672,8 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
#endif
uint8_t const *p_desc = _audiod_fct[i].p_desc;
uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
while (p_desc < p_desc_end)
// Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
while (p_desc_end - p_desc > 0)
{
if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT)
{
@@ -1916,7 +1923,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN;
// p_desc starts at required interface with alternate setting zero
while (p_desc < p_desc_end)
// Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
while (p_desc_end - p_desc > 0)
{
// Find correct interface
if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == alt)
@@ -1926,7 +1934,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
#endif
// From this point forward follow the EP descriptors associated to the current alternate setting interface - Open EPs if necessary
uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints;
while (foundEPs < nEps && p_desc < p_desc_end)
// Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
while (foundEPs < nEps && (p_desc_end - p_desc > 0))
{
if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT)
{
@@ -1955,8 +1964,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
// Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap
#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / (audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx))
* (audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx));
const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / (audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx))
* (audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx));
for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
{
tu_fifo_config(&audio->tx_supp_ff[cnt], audio->tx_supp_ff[cnt].buffer, active_fifo_depth, 1, true);
@@ -1986,7 +1995,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
// Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sampe_rx) * audio->n_bytes_per_sampe_rx;
const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sample_rx) * audio->n_bytes_per_sample_rx;
for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++)
{
tu_fifo_config(&audio->rx_supp_ff[cnt], audio->rx_supp_ff[cnt].buffer, active_fifo_depth, 1, true);
@@ -2584,7 +2593,8 @@ static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio
p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength;
uint8_t tmp = 0;
while (p_desc < p_desc_end)
// Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
while (p_desc_end - p_desc > 0)
{
// We assume the number of alternate settings is increasing thus we return the index of alternate setting zero!
if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0)
@@ -2637,7 +2647,8 @@ static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *
uint8_t const *p_desc_end = ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength + p_desc;
p_desc = tu_desc_next(p_desc); // Get past CS AC descriptor
while (p_desc < p_desc_end)
// Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
while (p_desc_end - p_desc > 0)
{
if (p_desc[3] == entityID) // Entity IDs are always at offset 3
{
@@ -2661,8 +2672,8 @@ static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id)
// Get pointer at beginning and end
uint8_t const *p_desc = _audiod_fct[i].p_desc;
uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
while (p_desc < p_desc_end)
// Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
while (p_desc_end - p_desc > 0)
{
if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf)
{
@@ -2690,7 +2701,8 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id)
uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc);
p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength;
while (p_desc < p_desc_end)
// Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
while (p_desc_end - p_desc > 0)
{
if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT && ((tusb_desc_endpoint_t const * )p_desc)->bEndpointAddress == ep)
{
@@ -2721,8 +2733,8 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const *
#endif
p_desc = tu_desc_next(p_desc); // Exclude standard AS interface descriptor of current alternate interface descriptor
while (p_desc < p_desc_end)
// Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
while (p_desc_end - p_desc > 0)
{
// Abort if follow up descriptor is a new standard interface descriptor - indicates the last AS descriptor was already finished
if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) break;
@@ -2771,14 +2783,14 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const *
#if CFG_TUD_AUDIO_ENABLE_EP_IN
if (as_itf == audio->ep_in_as_intf_num)
{
audio->n_bytes_per_sampe_tx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize;
audio->n_bytes_per_sample_tx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize;
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
if (as_itf == audio->ep_out_as_intf_num)
{
audio->n_bytes_per_sampe_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize;
audio->n_bytes_per_sample_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize;
}
#endif
}
@@ -2797,7 +2809,7 @@ static bool audiod_calc_tx_packet_sz(audiod_function_t* audio)
{
TU_VERIFY(audio->format_type_tx == AUDIO_FORMAT_TYPE_I);
TU_VERIFY(audio->n_channels_tx);
TU_VERIFY(audio->n_bytes_per_sampe_tx);
TU_VERIFY(audio->n_bytes_per_sample_tx);
TU_VERIFY(audio->interval_tx);
TU_VERIFY(audio->sample_rate_tx);
@@ -2806,9 +2818,9 @@ static bool audiod_calc_tx_packet_sz(audiod_function_t* audio)
const uint16_t sample_normimal = (uint16_t)(audio->sample_rate_tx * interval / ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000));
const uint16_t sample_reminder = (uint16_t)(audio->sample_rate_tx * interval % ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000));
const uint16_t packet_sz_tx_min = (uint16_t)((sample_normimal - 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx);
const uint16_t packet_sz_tx_norm = (uint16_t)(sample_normimal * audio->n_channels_tx * audio->n_bytes_per_sampe_tx);
const uint16_t packet_sz_tx_max = (uint16_t)((sample_normimal + 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx);
const uint16_t packet_sz_tx_min = (uint16_t)((sample_normimal - 1) * audio->n_channels_tx * audio->n_bytes_per_sample_tx);
const uint16_t packet_sz_tx_norm = (uint16_t)(sample_normimal * audio->n_channels_tx * audio->n_bytes_per_sample_tx);
const uint16_t packet_sz_tx_max = (uint16_t)((sample_normimal + 1) * audio->n_channels_tx * audio->n_bytes_per_sample_tx);
// Endpoint size must larger than packet size
TU_ASSERT(packet_sz_tx_max <= audio->ep_in_sz);

View File

@@ -45,8 +45,7 @@
//--------------------------------------------------------------------+
#define BULK_PACKET_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
typedef struct
{
typedef struct {
uint8_t itf_num;
uint8_t ep_notif;
uint8_t ep_in;
@@ -56,7 +55,7 @@ typedef struct
uint8_t line_state;
/*------------- From this point, data is not cleared by bus reset -------------*/
char wanted_char;
char wanted_char;
TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding;
// FIFO
@@ -72,19 +71,22 @@ typedef struct
// Endpoint Transfer buffer
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EP_BUFSIZE];
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CDC_EP_BUFSIZE];
}cdcd_interface_t;
} cdcd_interface_t;
#define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, wanted_char)
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
CFG_TUD_MEM_SECTION tu_static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
CFG_TUD_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
static tud_cdc_configure_fifo_t _cdcd_fifo_cfg;
static bool _prep_out_transaction (cdcd_interface_t* p_cdc)
{
static bool _prep_out_transaction (cdcd_interface_t* p_cdc) {
uint8_t const rhport = 0;
// Skip if usb is not ready yet
TU_VERIFY(tud_ready() && p_cdc->ep_out);
uint16_t available = tu_fifo_remaining(&p_cdc->rx_ff);
// Prepare for incoming data but only allow what we can store in the ring buffer.
@@ -99,14 +101,11 @@ static bool _prep_out_transaction (cdcd_interface_t* p_cdc)
// fifo can be changed before endpoint is claimed
available = tu_fifo_remaining(&p_cdc->rx_ff);
if ( available >= sizeof(p_cdc->epout_buf) )
{
if ( available >= sizeof(p_cdc->epout_buf) ) {
return usbd_edpt_xfer(rhport, p_cdc->ep_out, p_cdc->epout_buf, sizeof(p_cdc->epout_buf));
}else
{
}else {
// Release endpoint since we don't make any transfer
usbd_edpt_release(rhport, p_cdc->ep_out);
return false;
}
}
@@ -114,51 +113,53 @@ static bool _prep_out_transaction (cdcd_interface_t* p_cdc)
//--------------------------------------------------------------------+
// APPLICATION API
//--------------------------------------------------------------------+
bool tud_cdc_n_connected(uint8_t itf)
{
bool tud_cdc_configure_fifo(tud_cdc_configure_fifo_t const* cfg) {
TU_VERIFY(cfg);
_cdcd_fifo_cfg = (*cfg);
return true;
}
bool tud_cdc_n_ready(uint8_t itf) {
return tud_ready() && _cdcd_itf[itf].ep_in != 0 && _cdcd_itf[itf].ep_out != 0;
}
bool tud_cdc_n_connected(uint8_t itf) {
// DTR (bit 0) active is considered as connected
return tud_ready() && tu_bit_test(_cdcd_itf[itf].line_state, 0);
}
uint8_t tud_cdc_n_get_line_state (uint8_t itf)
{
uint8_t tud_cdc_n_get_line_state(uint8_t itf) {
return _cdcd_itf[itf].line_state;
}
void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding)
{
void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding) {
(*coding) = _cdcd_itf[itf].line_coding;
}
void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted)
{
void tud_cdc_n_set_wanted_char(uint8_t itf, char wanted) {
_cdcd_itf[itf].wanted_char = wanted;
}
//--------------------------------------------------------------------+
// READ API
//--------------------------------------------------------------------+
uint32_t tud_cdc_n_available(uint8_t itf)
{
uint32_t tud_cdc_n_available(uint8_t itf) {
return tu_fifo_count(&_cdcd_itf[itf].rx_ff);
}
uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize)
{
uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize) {
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX));
_prep_out_transaction(p_cdc);
return num_read;
}
bool tud_cdc_n_peek(uint8_t itf, uint8_t* chr)
{
bool tud_cdc_n_peek(uint8_t itf, uint8_t* chr) {
return tu_fifo_peek(&_cdcd_itf[itf].rx_ff, chr);
}
void tud_cdc_n_read_flush (uint8_t itf)
{
void tud_cdc_n_read_flush(uint8_t itf) {
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
tu_fifo_clear(&p_cdc->rx_ff);
_prep_out_transaction(p_cdc);
@@ -167,16 +168,15 @@ void tud_cdc_n_read_flush (uint8_t itf)
//--------------------------------------------------------------------+
// WRITE API
//--------------------------------------------------------------------+
uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize)
{
uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) {
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX));
// flush if queue more than packet size
if ( tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE
#if CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE
|| tu_fifo_full(&p_cdc->tx_ff) // check full if fifo size is less than packet size
#endif
if (tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE
#if CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE
|| tu_fifo_full(&p_cdc->tx_ff) // check full if fifo size is less than packet size
#endif
) {
tud_cdc_n_write_flush(itf);
}
@@ -184,30 +184,27 @@ uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize)
return ret;
}
uint32_t tud_cdc_n_write_flush (uint8_t itf)
{
uint32_t tud_cdc_n_write_flush(uint8_t itf) {
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
// Skip if usb is not ready yet
TU_VERIFY( tud_ready(), 0 );
TU_VERIFY(tud_ready(), 0);
// No data to send
if ( !tu_fifo_count(&p_cdc->tx_ff) ) return 0;
if (!tu_fifo_count(&p_cdc->tx_ff)) return 0;
uint8_t const rhport = 0;
// Claim the endpoint
TU_VERIFY( usbd_edpt_claim(rhport, p_cdc->ep_in), 0 );
TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_in), 0);
// Pull data from FIFO
uint16_t const count = tu_fifo_read_n(&p_cdc->tx_ff, p_cdc->epin_buf, sizeof(p_cdc->epin_buf));
if ( count )
{
TU_ASSERT( usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 );
if (count) {
TU_ASSERT(usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0);
return count;
}else
{
} else {
// Release endpoint since we don't make any transfer
// Note: data is dropped if terminal is not connected
usbd_edpt_release(rhport, p_cdc->ep_in);
@@ -215,33 +212,30 @@ uint32_t tud_cdc_n_write_flush (uint8_t itf)
}
}
uint32_t tud_cdc_n_write_available (uint8_t itf)
{
uint32_t tud_cdc_n_write_available(uint8_t itf) {
return tu_fifo_remaining(&_cdcd_itf[itf].tx_ff);
}
bool tud_cdc_n_write_clear (uint8_t itf)
{
bool tud_cdc_n_write_clear(uint8_t itf) {
return tu_fifo_clear(&_cdcd_itf[itf].tx_ff);
}
//--------------------------------------------------------------------+
// USBD Driver API
//--------------------------------------------------------------------+
void cdcd_init(void)
{
void cdcd_init(void) {
tu_memclr(_cdcd_itf, sizeof(_cdcd_itf));
tu_memclr(&_cdcd_fifo_cfg, sizeof(_cdcd_fifo_cfg));
for(uint8_t i=0; i<CFG_TUD_CDC; i++)
{
for (uint8_t i = 0; i < CFG_TUD_CDC; i++) {
cdcd_interface_t* p_cdc = &_cdcd_itf[i];
p_cdc->wanted_char = (char) -1;
// default line coding is : stop bit = 1, parity = none, data bits = 8
p_cdc->line_coding.bit_rate = 115200;
p_cdc->line_coding.bit_rate = 115200;
p_cdc->line_coding.stop_bits = 0;
p_cdc->line_coding.parity = 0;
p_cdc->line_coding.parity = 0;
p_cdc->line_coding.data_bits = 8;
// Config RX fifo
@@ -285,35 +279,28 @@ bool cdcd_deinit(void) {
return true;
}
void cdcd_reset(uint8_t rhport)
{
void cdcd_reset(uint8_t rhport) {
(void) rhport;
for(uint8_t i=0; i<CFG_TUD_CDC; i++)
{
for (uint8_t i = 0; i < CFG_TUD_CDC; i++) {
cdcd_interface_t* p_cdc = &_cdcd_itf[i];
tu_memclr(p_cdc, ITF_MEM_RESET_SIZE);
tu_fifo_clear(&p_cdc->rx_ff);
#if !CFG_TUD_CDC_PERSISTENT_TX_BUFF
tu_fifo_clear(&p_cdc->tx_ff);
#endif
if (!_cdcd_fifo_cfg.rx_persistent) tu_fifo_clear(&p_cdc->rx_ff);
if (!_cdcd_fifo_cfg.tx_persistent) tu_fifo_clear(&p_cdc->tx_ff);
tu_fifo_set_overwritable(&p_cdc->tx_ff, true);
}
}
uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
{
uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) {
// Only support ACM subclass
TU_VERIFY( TUSB_CLASS_CDC == itf_desc->bInterfaceClass &&
CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass, 0);
// Find available interface
cdcd_interface_t * p_cdc = NULL;
for(uint8_t cdc_id=0; cdc_id<CFG_TUD_CDC; cdc_id++)
{
if ( _cdcd_itf[cdc_id].ep_in == 0 )
{
cdcd_interface_t* p_cdc = NULL;
for (uint8_t cdc_id = 0; cdc_id < CFG_TUD_CDC; cdc_id++) {
if (_cdcd_itf[cdc_id].ep_in == 0) {
p_cdc = &_cdcd_itf[cdc_id];
break;
}
@@ -324,39 +311,36 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
p_cdc->itf_num = itf_desc->bInterfaceNumber;
uint16_t drv_len = sizeof(tusb_desc_interface_t);
uint8_t const * p_desc = tu_desc_next( itf_desc );
uint8_t const* p_desc = tu_desc_next(itf_desc);
// Communication Functional Descriptors
while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len )
{
while (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len) {
drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
p_desc = tu_desc_next(p_desc);
}
if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
{
if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) {
// notification endpoint
tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc;
TU_ASSERT( usbd_edpt_open(rhport, desc_ep), 0 );
TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0);
p_cdc->ep_notif = desc_ep->bEndpointAddress;
drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
p_desc = tu_desc_next(p_desc);
}
//------------- Data Interface (if any) -------------//
if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) &&
(TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
{
if ((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) &&
(TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const*) p_desc)->bInterfaceClass)) {
// next to endpoint descriptor
drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
p_desc = tu_desc_next(p_desc);
// Open endpoint pair
TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in), 0 );
TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in), 0);
drv_len += 2*sizeof(tusb_desc_endpoint_t);
drv_len += 2 * sizeof(tusb_desc_endpoint_t);
}
// Prepare for incoming data
@@ -368,8 +352,7 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
// Invoked when a control transfer occurred on an interface of this class
// Driver response accordingly to the request and the transfer stage (setup/data/ack)
// return false to stall control endpoint (e.g unsupported request)
bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
{
bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) {
// Handle class request only
TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
@@ -377,42 +360,33 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
cdcd_interface_t* p_cdc = _cdcd_itf;
// Identify which interface to use
for ( ; ; itf++, p_cdc++)
{
for (;; itf++, p_cdc++) {
if (itf >= TU_ARRAY_SIZE(_cdcd_itf)) return false;
if ( p_cdc->itf_num == request->wIndex ) break;
if (p_cdc->itf_num == request->wIndex) break;
}
switch ( request->bRequest )
{
switch (request->bRequest) {
case CDC_REQUEST_SET_LINE_CODING:
if (stage == CONTROL_STAGE_SETUP)
{
if (stage == CONTROL_STAGE_SETUP) {
TU_LOG_DRV(" Set Line Coding\r\n");
tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
} else if (stage == CONTROL_STAGE_ACK) {
if (tud_cdc_line_coding_cb) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding);
}
else if ( stage == CONTROL_STAGE_ACK)
{
if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding);
}
break;
break;
case CDC_REQUEST_GET_LINE_CODING:
if (stage == CONTROL_STAGE_SETUP)
{
if (stage == CONTROL_STAGE_SETUP) {
TU_LOG_DRV(" Get Line Coding\r\n");
tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
}
break;
break;
case CDC_REQUEST_SET_CONTROL_LINE_STATE:
if (stage == CONTROL_STAGE_SETUP)
{
if (stage == CONTROL_STAGE_SETUP) {
tud_control_status(rhport, request);
}
else if (stage == CONTROL_STAGE_ACK)
{
} else if (stage == CONTROL_STAGE_ACK) {
// CDC PSTN v1.2 section 6.3.12
// Bit 0: Indicates if DTE is present or not.
// This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR (Data Terminal Ready)
@@ -429,61 +403,54 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
TU_LOG_DRV(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts);
// Invoke callback
if ( tud_cdc_line_state_cb ) tud_cdc_line_state_cb(itf, dtr, rts);
if (tud_cdc_line_state_cb) tud_cdc_line_state_cb(itf, dtr, rts);
}
break;
case CDC_REQUEST_SEND_BREAK:
if (stage == CONTROL_STAGE_SETUP)
{
tud_control_status(rhport, request);
}
else if (stage == CONTROL_STAGE_ACK)
{
TU_LOG_DRV(" Send Break\r\n");
if ( tud_cdc_send_break_cb ) tud_cdc_send_break_cb(itf, request->wValue);
}
break;
break;
default: return false; // stall unsupported request
case CDC_REQUEST_SEND_BREAK:
if (stage == CONTROL_STAGE_SETUP) {
tud_control_status(rhport, request);
} else if (stage == CONTROL_STAGE_ACK) {
TU_LOG_DRV(" Send Break\r\n");
if (tud_cdc_send_break_cb) tud_cdc_send_break_cb(itf, request->wValue);
}
break;
default:
return false; // stall unsupported request
}
return true;
}
bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
{
bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
(void) result;
uint8_t itf;
cdcd_interface_t* p_cdc;
// Identify which interface to use
for (itf = 0; itf < CFG_TUD_CDC; itf++)
{
for (itf = 0; itf < CFG_TUD_CDC; itf++) {
p_cdc = &_cdcd_itf[itf];
if ( ( ep_addr == p_cdc->ep_out ) || ( ep_addr == p_cdc->ep_in ) ) break;
if ((ep_addr == p_cdc->ep_out) || (ep_addr == p_cdc->ep_in)) break;
}
TU_ASSERT(itf < CFG_TUD_CDC);
// Received new data
if ( ep_addr == p_cdc->ep_out )
{
if (ep_addr == p_cdc->ep_out) {
tu_fifo_write_n(&p_cdc->rx_ff, p_cdc->epout_buf, (uint16_t) xferred_bytes);
// Check for wanted char and invoke callback if needed
if ( tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1) )
{
for ( uint32_t i = 0; i < xferred_bytes; i++ )
{
if ( (p_cdc->wanted_char == p_cdc->epout_buf[i]) && !tu_fifo_empty(&p_cdc->rx_ff) )
{
if (tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1)) {
for (uint32_t i = 0; i < xferred_bytes; i++) {
if ((p_cdc->wanted_char == p_cdc->epout_buf[i]) && !tu_fifo_empty(&p_cdc->rx_ff)) {
tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char);
}
}
}
// invoke receive callback (if there is still data)
if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf);
if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff)) tud_cdc_rx_cb(itf);
// prepare for OUT transaction
_prep_out_transaction(p_cdc);
@@ -492,19 +459,15 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
// Data sent to host, we continue to fetch from tx fifo to send.
// Note: This will cause incorrect baudrate set in line coding.
// Though maybe the baudrate is not really important !!!
if ( ep_addr == p_cdc->ep_in )
{
if (ep_addr == p_cdc->ep_in) {
// invoke transmit callback to possibly refill tx fifo
if ( tud_cdc_tx_complete_cb ) tud_cdc_tx_complete_cb(itf);
if (tud_cdc_tx_complete_cb) tud_cdc_tx_complete_cb(itf);
if ( 0 == tud_cdc_n_write_flush(itf) )
{
if (0 == tud_cdc_n_write_flush(itf)) {
// If there is no data left, a ZLP should be sent if
// xferred_bytes is multiple of EP Packet size and not zero
if ( !tu_fifo_count(&p_cdc->tx_ff) && xferred_bytes && (0 == (xferred_bytes & (BULK_PACKET_SIZE-1))) )
{
if ( usbd_edpt_claim(rhport, p_cdc->ep_in) )
{
if (!tu_fifo_count(&p_cdc->tx_ff) && xferred_bytes && (0 == (xferred_bytes & (BULK_PACKET_SIZE - 1)))) {
if (usbd_edpt_claim(rhport, p_cdc->ep_in)) {
usbd_edpt_xfer(rhport, p_cdc->ep_in, NULL, 0);
}
}

View File

@@ -24,8 +24,8 @@
* This file is part of the TinyUSB stack.
*/
#ifndef _TUSB_CDC_DEVICE_H_
#define _TUSB_CDC_DEVICE_H_
#ifndef TUSB_CDC_DEVICE_H_
#define TUSB_CDC_DEVICE_H_
#include "cdc.h"
@@ -41,94 +41,148 @@
#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#endif
// By default the TX fifo buffer is cleared on connect / bus reset.
// Enable this to persist any data in the fifo instead.
#ifndef CFG_TUD_CDC_PERSISTENT_TX_BUFF
#define CFG_TUD_CDC_PERSISTENT_TX_BUFF (0)
#endif
#ifdef __cplusplus
extern "C" {
#endif
/** \addtogroup CDC_Serial Serial
* @{
* \defgroup CDC_Serial_Device Device
* @{ */
//--------------------------------------------------------------------+
// Driver Configuration
//--------------------------------------------------------------------+
typedef struct TU_ATTR_PACKED {
uint8_t rx_persistent : 1; // keep rx fifo on bus reset or disconnect
uint8_t tx_persistent : 1; // keep tx fifo on bus reset or disconnect
} tud_cdc_configure_fifo_t;
// Configure CDC FIFOs behavior
bool tud_cdc_configure_fifo(tud_cdc_configure_fifo_t const* cfg);
//--------------------------------------------------------------------+
// Application API (Multiple Ports)
// CFG_TUD_CDC > 1
// Application API (Multiple Ports) i.e. CFG_TUD_CDC > 1
//--------------------------------------------------------------------+
// Check if interface is ready
bool tud_cdc_n_ready(uint8_t itf);
// Check if terminal is connected to this port
bool tud_cdc_n_connected (uint8_t itf);
bool tud_cdc_n_connected(uint8_t itf);
// Get current line state. Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send)
uint8_t tud_cdc_n_get_line_state (uint8_t itf);
uint8_t tud_cdc_n_get_line_state(uint8_t itf);
// Get current line encoding: bit rate, stop bits parity etc ..
void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding);
void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding);
// Set special character that will trigger tud_cdc_rx_wanted_cb() callback on receiving
void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted);
void tud_cdc_n_set_wanted_char(uint8_t itf, char wanted);
// Get the number of bytes available for reading
uint32_t tud_cdc_n_available (uint8_t itf);
uint32_t tud_cdc_n_available(uint8_t itf);
// Read received bytes
uint32_t tud_cdc_n_read (uint8_t itf, void* buffer, uint32_t bufsize);
uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize);
// Read a byte, return -1 if there is none
static inline
int32_t tud_cdc_n_read_char (uint8_t itf);
TU_ATTR_ALWAYS_INLINE static inline int32_t tud_cdc_n_read_char(uint8_t itf) {
uint8_t ch;
return tud_cdc_n_read(itf, &ch, 1) ? (int32_t) ch : -1;
}
// Clear the received FIFO
void tud_cdc_n_read_flush (uint8_t itf);
void tud_cdc_n_read_flush(uint8_t itf);
// Get a byte from FIFO without removing it
bool tud_cdc_n_peek (uint8_t itf, uint8_t* ui8);
bool tud_cdc_n_peek(uint8_t itf, uint8_t* ui8);
// Write bytes to TX FIFO, data may remain in the FIFO for a while
uint32_t tud_cdc_n_write (uint8_t itf, void const* buffer, uint32_t bufsize);
uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize);
// Write a byte
static inline
uint32_t tud_cdc_n_write_char (uint8_t itf, char ch);
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_n_write_char(uint8_t itf, char ch) {
return tud_cdc_n_write(itf, &ch, 1);
}
// Write a null-terminated string
static inline
uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str);
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_n_write_str(uint8_t itf, char const* str) {
return tud_cdc_n_write(itf, str, strlen(str));
}
// Force sending data if possible, return number of forced bytes
uint32_t tud_cdc_n_write_flush (uint8_t itf);
uint32_t tud_cdc_n_write_flush(uint8_t itf);
// Return the number of bytes (characters) available for writing to TX FIFO buffer in a single n_write operation.
uint32_t tud_cdc_n_write_available (uint8_t itf);
uint32_t tud_cdc_n_write_available(uint8_t itf);
// Clear the transmit FIFO
bool tud_cdc_n_write_clear (uint8_t itf);
bool tud_cdc_n_write_clear(uint8_t itf);
//--------------------------------------------------------------------+
// Application API (Single Port)
//--------------------------------------------------------------------+
static inline bool tud_cdc_connected (void);
static inline uint8_t tud_cdc_get_line_state (void);
static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding);
static inline void tud_cdc_set_wanted_char (char wanted);
static inline uint32_t tud_cdc_available (void);
static inline int32_t tud_cdc_read_char (void);
static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize);
static inline void tud_cdc_read_flush (void);
static inline bool tud_cdc_peek (uint8_t* ui8);
TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_ready(void) {
return tud_cdc_n_ready(0);
}
static inline uint32_t tud_cdc_write_char (char ch);
static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize);
static inline uint32_t tud_cdc_write_str (char const* str);
static inline uint32_t tud_cdc_write_flush (void);
static inline uint32_t tud_cdc_write_available (void);
static inline bool tud_cdc_write_clear (void);
TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_connected(void) {
return tud_cdc_n_connected(0);
}
TU_ATTR_ALWAYS_INLINE static inline uint8_t tud_cdc_get_line_state(void) {
return tud_cdc_n_get_line_state(0);
}
TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_get_line_coding(cdc_line_coding_t* coding) {
tud_cdc_n_get_line_coding(0, coding);
}
TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_set_wanted_char(char wanted) {
tud_cdc_n_set_wanted_char(0, wanted);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_available(void) {
return tud_cdc_n_available(0);
}
TU_ATTR_ALWAYS_INLINE static inline int32_t tud_cdc_read_char(void) {
return tud_cdc_n_read_char(0);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_read(void* buffer, uint32_t bufsize) {
return tud_cdc_n_read(0, buffer, bufsize);
}
TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_read_flush(void) {
tud_cdc_n_read_flush(0);
}
TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_peek(uint8_t* ui8) {
return tud_cdc_n_peek(0, ui8);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write_char(char ch) {
return tud_cdc_n_write_char(0, ch);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write(void const* buffer, uint32_t bufsize) {
return tud_cdc_n_write(0, buffer, bufsize);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write_str(char const* str) {
return tud_cdc_n_write_str(0, str);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write_flush(void) {
return tud_cdc_n_write_flush(0);
}
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write_available(void) {
return tud_cdc_n_write_available(0);
}
TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_write_clear(void) {
return tud_cdc_n_write_clear(0);
}
//--------------------------------------------------------------------+
// Application Callback API (weak is optional)
@@ -152,103 +206,6 @@ TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p
// Invoked when received send break
TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms);
//--------------------------------------------------------------------+
// Inline Functions
//--------------------------------------------------------------------+
static inline int32_t tud_cdc_n_read_char (uint8_t itf)
{
uint8_t ch;
return tud_cdc_n_read(itf, &ch, 1) ? (int32_t) ch : -1;
}
static inline uint32_t tud_cdc_n_write_char(uint8_t itf, char ch)
{
return tud_cdc_n_write(itf, &ch, 1);
}
static inline uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str)
{
return tud_cdc_n_write(itf, str, strlen(str));
}
static inline bool tud_cdc_connected (void)
{
return tud_cdc_n_connected(0);
}
static inline uint8_t tud_cdc_get_line_state (void)
{
return tud_cdc_n_get_line_state(0);
}
static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding)
{
tud_cdc_n_get_line_coding(0, coding);
}
static inline void tud_cdc_set_wanted_char (char wanted)
{
tud_cdc_n_set_wanted_char(0, wanted);
}
static inline uint32_t tud_cdc_available (void)
{
return tud_cdc_n_available(0);
}
static inline int32_t tud_cdc_read_char (void)
{
return tud_cdc_n_read_char(0);
}
static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize)
{
return tud_cdc_n_read(0, buffer, bufsize);
}
static inline void tud_cdc_read_flush (void)
{
tud_cdc_n_read_flush(0);
}
static inline bool tud_cdc_peek (uint8_t* ui8)
{
return tud_cdc_n_peek(0, ui8);
}
static inline uint32_t tud_cdc_write_char (char ch)
{
return tud_cdc_n_write_char(0, ch);
}
static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize)
{
return tud_cdc_n_write(0, buffer, bufsize);
}
static inline uint32_t tud_cdc_write_str (char const* str)
{
return tud_cdc_n_write_str(0, str);
}
static inline uint32_t tud_cdc_write_flush (void)
{
return tud_cdc_n_write_flush(0);
}
static inline uint32_t tud_cdc_write_available(void)
{
return tud_cdc_n_write_available(0);
}
static inline bool tud_cdc_write_clear(void)
{
return tud_cdc_n_write_clear(0);
}
/** @} */
/** @} */
//--------------------------------------------------------------------+
// INTERNAL USBD-CLASS DRIVER API
//--------------------------------------------------------------------+

View File

@@ -762,7 +762,7 @@ enum {
HID_USAGE_PAGE_ALPHA_DISPLAY = 0x14,
HID_USAGE_PAGE_MEDICAL = 0x40,
HID_USAGE_PAGE_LIGHTING_AND_ILLUMINATION = 0x59,
HID_USAGE_PAGE_MONITOR = 0x80, //0x80 - 0x83
HID_USAGE_PAGE_MONITOR = 0x80, // 0x80 - 0x83
HID_USAGE_PAGE_POWER = 0x84, // 0x084 - 0x87
HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c,
HID_USAGE_PAGE_SCALE = 0x8d,
@@ -770,7 +770,7 @@ enum {
HID_USAGE_PAGE_CAMERA = 0x90,
HID_USAGE_PAGE_ARCADE = 0x91,
HID_USAGE_PAGE_FIDO = 0xF1D0, // FIDO alliance HID usage page
HID_USAGE_PAGE_VENDOR = 0xFF00 // 0xFF00 - 0xFFFF
HID_USAGE_PAGE_VENDOR = 0xFF00 // 0xFF00 - 0xFFFF
};
/// HID Usage Table - Table 6: Generic Desktop Page

View File

@@ -46,43 +46,68 @@ typedef struct {
uint8_t itf_protocol; // Boot mouse or keyboard
uint16_t report_desc_len;
CFG_TUSB_MEM_ALIGN uint8_t protocol_mode; // Boot (0) or Report protocol (1)
CFG_TUSB_MEM_ALIGN uint8_t idle_rate; // up to application to handle idle rate
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE];
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE];
CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf[CFG_TUD_HID_EP_BUFSIZE];
uint8_t protocol_mode; // Boot (0) or Report protocol (1)
uint8_t idle_rate; // up to application to handle idle rate
// TODO save hid descriptor since host can specifically request this after enumeration
// Note: HID descriptor may be not available from application after enumeration
tusb_hid_descriptor_hid_t const *hid_descriptor;
uint8_t ctrl_buf[CFG_TUD_HID_EP_BUFSIZE];
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE];
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE];
} hidd_interface_t;
CFG_TUD_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID];
/*------------- Helpers -------------*/
static inline uint8_t get_index_by_itfnum(uint8_t itf_num)
{
TU_ATTR_ALWAYS_INLINE static inline uint8_t get_index_by_itfnum(uint8_t itf_num) {
for (uint8_t i = 0; i < CFG_TUD_HID; i++) {
if (itf_num == _hidd_itf[i].itf_num)
if (itf_num == _hidd_itf[i].itf_num) {
return i;
}
}
return 0xFF;
}
//--------------------------------------------------------------------+
// Weak stubs: invoked if no strong implementation is available
//--------------------------------------------------------------------+
TU_ATTR_WEAK void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol) {
(void) instance;
(void) protocol;
}
TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate) {
(void) instance;
(void) idle_rate;
return true;
}
TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len) {
(void) instance;
(void) report;
(void) len;
}
// Invoked when a transfer wasn't successful
TU_ATTR_WEAK void tud_hid_report_failed_cb(uint8_t instance, hid_report_type_t report_type, uint8_t const* report, uint16_t xferred_bytes) {
(void) instance;
(void) report_type;
(void) report;
(void) xferred_bytes;
}
//--------------------------------------------------------------------+
// APPLICATION API
//--------------------------------------------------------------------+
bool tud_hid_n_ready(uint8_t instance)
{
bool tud_hid_n_ready(uint8_t instance) {
uint8_t const rhport = 0;
uint8_t const ep_in = _hidd_itf[instance].ep_in;
return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(rhport, ep_in);
}
bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const *report, uint16_t len)
{
bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const *report, uint16_t len) {
uint8_t const rhport = 0;
hidd_interface_t *p_hid = &_hidd_itf[instance];
@@ -101,14 +126,16 @@ bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const *report, u
return usbd_edpt_xfer(rhport, p_hid->ep_in, p_hid->epin_buf, len);
}
uint8_t tud_hid_n_interface_protocol(uint8_t instance) { return _hidd_itf[instance].itf_protocol; }
uint8_t tud_hid_n_interface_protocol(uint8_t instance) {
return _hidd_itf[instance].itf_protocol;
}
uint8_t tud_hid_n_get_protocol(uint8_t instance) { return _hidd_itf[instance].protocol_mode; }
uint8_t tud_hid_n_get_protocol(uint8_t instance) {
return _hidd_itf[instance].protocol_mode;
}
bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6])
{
bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6]) {
hid_keyboard_report_t report;
report.modifier = modifier;
report.reserved = 0;
@@ -121,8 +148,8 @@ bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modi
return tud_hid_n_report(instance, report_id, &report, sizeof(report));
}
bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal)
{
bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id,
uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) {
hid_mouse_report_t report = {
.buttons = buttons,
.x = x,
@@ -134,8 +161,8 @@ bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons
return tud_hid_n_report(instance, report_id, &report, sizeof(report));
}
bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal)
{
bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id,
uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) {
hid_abs_mouse_report_t report = {
.buttons = buttons,
.x = x,
@@ -146,8 +173,8 @@ bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t but
return tud_hid_n_report(instance, report_id, &report, sizeof(report));
}
bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons)
{
bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id,
int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) {
hid_gamepad_report_t report = {
.x = x,
.y = y,
@@ -165,28 +192,25 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int
//--------------------------------------------------------------------+
// USBD-CLASS API
//--------------------------------------------------------------------+
void hidd_init(void)
{
void hidd_init(void) {
hidd_reset(0);
}
bool hidd_deinit(void)
{
bool hidd_deinit(void) {
return true;
}
void hidd_reset(uint8_t rhport)
{
void hidd_reset(uint8_t rhport) {
(void)rhport;
tu_memclr(_hidd_itf, sizeof(_hidd_itf));
}
uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
{
uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16_t max_len) {
TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0);
// len = interface + hid + n*endpoints
uint16_t const drv_len = (uint16_t)(sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) +
desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
TU_ASSERT(max_len >= drv_len, 0);
// Find available interface
@@ -211,8 +235,9 @@ uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16
p_desc = tu_desc_next(p_desc);
TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_INTERRUPT, &p_hid->ep_out, &p_hid->ep_in), 0);
if (desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT)
if (desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT) {
p_hid->itf_protocol = desc_itf->bInterfaceProtocol;
}
p_hid->protocol_mode = HID_PROTOCOL_REPORT; // Per Specs: default is report mode
p_hid->itf_num = desc_itf->bInterfaceNumber;
@@ -234,8 +259,7 @@ uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16
// Invoked when a control transfer occurred on an interface of this class
// Driver response accordingly to the request and the transfer stage (setup/data/ack)
// return false to stall control endpoint (e.g unsupported request)
bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
{
bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) {
TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE);
uint8_t const hid_itf = get_index_by_itfnum((uint8_t)request->wIndex);
@@ -262,90 +286,82 @@ bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
} else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) {
//------------- Class Specific Request -------------//
switch (request->bRequest) {
case HID_REQ_CONTROL_GET_REPORT:
if (stage == CONTROL_STAGE_SETUP) {
uint8_t const report_type = tu_u16_high(request->wValue);
uint8_t const report_id = tu_u16_low(request->wValue);
case HID_REQ_CONTROL_GET_REPORT:
if (stage == CONTROL_STAGE_SETUP) {
uint8_t const report_type = tu_u16_high(request->wValue);
uint8_t const report_id = tu_u16_low(request->wValue);
uint8_t *report_buf = p_hid->ctrl_buf;
uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
uint8_t* report_buf = p_hid->ctrl_buf;
uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
uint16_t xferlen = 0;
uint16_t xferlen = 0;
// If host request a specific Report ID, add ID to as 1 byte of response
if ((report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1)) {
*report_buf++ = report_id;
req_len--;
xferlen++;
}
// If host request a specific Report ID, add ID to as 1 byte of response
if ((report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1)) {
*report_buf++ = report_id;
req_len--;
xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len);
TU_ASSERT(xferlen > 0);
xferlen++;
tud_control_xfer(rhport, request, p_hid->ctrl_buf, xferlen);
}
break;
xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t)report_type, report_buf, req_len);
TU_ASSERT(xferlen > 0);
case HID_REQ_CONTROL_SET_REPORT:
if (stage == CONTROL_STAGE_SETUP) {
TU_VERIFY(request->wLength <= sizeof(p_hid->ctrl_buf));
tud_control_xfer(rhport, request, p_hid->ctrl_buf, request->wLength);
} else if (stage == CONTROL_STAGE_ACK) {
uint8_t const report_type = tu_u16_high(request->wValue);
uint8_t const report_id = tu_u16_low(request->wValue);
tud_control_xfer(rhport, request, p_hid->ctrl_buf, xferlen);
}
break;
uint8_t const* report_buf = p_hid->ctrl_buf;
uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
case HID_REQ_CONTROL_SET_REPORT:
if (stage == CONTROL_STAGE_SETUP) {
TU_VERIFY(request->wLength <= sizeof(p_hid->ctrl_buf));
tud_control_xfer(rhport, request, p_hid->ctrl_buf, request->wLength);
} else if (stage == CONTROL_STAGE_ACK) {
uint8_t const report_type = tu_u16_high(request->wValue);
uint8_t const report_id = tu_u16_low(request->wValue);
// If host request a specific Report ID, extract report ID in buffer before invoking callback
if ((report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0])) {
report_buf++;
report_len--;
}
uint8_t const *report_buf = p_hid->ctrl_buf;
uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
// If host request a specific Report ID, extract report ID in buffer before invoking callback
if ((report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0])) {
report_buf++;
report_len--;
tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, report_len);
}
break;
tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t)report_type, report_buf, report_len);
}
break;
case HID_REQ_CONTROL_SET_IDLE:
if (stage == CONTROL_STAGE_SETUP) {
p_hid->idle_rate = tu_u16_high(request->wValue);
if (tud_hid_set_idle_cb) {
// stall request if callback return false
TU_VERIFY(tud_hid_set_idle_cb(hid_itf, p_hid->idle_rate));
case HID_REQ_CONTROL_SET_IDLE:
if (stage == CONTROL_STAGE_SETUP) {
p_hid->idle_rate = tu_u16_high(request->wValue);
TU_VERIFY(tud_hid_set_idle_cb(hid_itf, p_hid->idle_rate)); // stall if false
tud_control_status(rhport, request);
}
break;
tud_control_status(rhport, request);
}
break;
case HID_REQ_CONTROL_GET_IDLE:
if (stage == CONTROL_STAGE_SETUP) {
// TODO idle rate of report
tud_control_xfer(rhport, request, &p_hid->idle_rate, 1);
}
break;
case HID_REQ_CONTROL_GET_IDLE:
if (stage == CONTROL_STAGE_SETUP) {
// TODO idle rate of report
tud_control_xfer(rhport, request, &p_hid->idle_rate, 1);
}
break;
case HID_REQ_CONTROL_GET_PROTOCOL:
if (stage == CONTROL_STAGE_SETUP) {
tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1);
}
break;
case HID_REQ_CONTROL_GET_PROTOCOL:
if (stage == CONTROL_STAGE_SETUP) {
tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1);
}
break;
case HID_REQ_CONTROL_SET_PROTOCOL:
if (stage == CONTROL_STAGE_SETUP) {
tud_control_status(rhport, request);
} else if (stage == CONTROL_STAGE_ACK) {
p_hid->protocol_mode = (uint8_t)request->wValue;
if (tud_hid_set_protocol_cb) {
case HID_REQ_CONTROL_SET_PROTOCOL:
if (stage == CONTROL_STAGE_SETUP) {
tud_control_status(rhport, request);
} else if (stage == CONTROL_STAGE_ACK) {
p_hid->protocol_mode = (uint8_t) request->wValue;
tud_hid_set_protocol_cb(hid_itf, p_hid->protocol_mode);
}
}
break;
break;
default:
return false; // stall unsupported request
default:
return false; // stall unsupported request
}
} else {
return false; // stall unsupported request
@@ -354,45 +370,35 @@ bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
return true;
}
bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
{
(void)result;
bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
uint8_t instance = 0;
hidd_interface_t *p_hid = _hidd_itf;
// Identify which interface to use
for (instance = 0; instance < CFG_TUD_HID; instance++) {
p_hid = &_hidd_itf[instance];
if ((ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in))
if ((ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in)) {
break;
}
}
TU_ASSERT(instance < CFG_TUD_HID);
// Check if there was a problem
if (XFER_RESULT_SUCCESS != result) { // Inform application about the issue
if (tud_hid_report_fail_cb) {
tud_hid_report_fail_cb(instance, ep_addr, (uint16_t)xferred_bytes);
}
// Allow a new transfer to be received if issue happened on an OUT endpoint
if (ep_addr == p_hid->ep_out) {
// Prepare the OUT endpoint to be able to receive a new transfer
TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
}
return true;
}
// Sent report successfully
if (ep_addr == p_hid->ep_in) {
if (tud_hid_report_complete_cb) {
tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t)xferred_bytes);
// Input report
if (XFER_RESULT_SUCCESS == result) {
tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t) xferred_bytes);
} else {
tud_hid_report_failed_cb(instance, HID_REPORT_TYPE_INPUT, p_hid->epin_buf, (uint16_t) xferred_bytes);
}
}
// Received report successfully
else if (ep_addr == p_hid->ep_out) {
tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t)xferred_bytes);
} else {
// Output report
if (XFER_RESULT_SUCCESS == result) {
tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t)xferred_bytes);
} else {
tud_hid_report_failed_cb(instance, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t) xferred_bytes);
}
// prepare for new transfer
TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
}

View File

@@ -24,8 +24,8 @@
* This file is part of the TinyUSB stack.
*/
#ifndef _TUSB_HID_DEVICE_H_
#define _TUSB_HID_DEVICE_H_
#ifndef TUSB_HID_DEVICE_H_
#define TUSB_HID_DEVICE_H_
#include "hid.h"
@@ -48,8 +48,7 @@
#endif
//--------------------------------------------------------------------+
// Application API (Multiple Instances)
// CFG_TUD_HID > 1
// Application API (Multiple Instances) i.e. CFG_TUD_HID > 1
//--------------------------------------------------------------------+
// Check if the interface is ready to use
@@ -76,12 +75,6 @@ bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons
// use template layout report as defined by hid_abs_mouse_report_t
bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal);
static inline bool tud_hid_abs_mouse_report(uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal)
{
return tud_hid_n_abs_mouse_report(0, report_id, buttons, x, y, vertical, horizontal);
}
// Gamepad: convenient helper to send gamepad report if application
// use template layout report TUD_HID_REPORT_DESC_GAMEPAD
bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons);
@@ -89,16 +82,40 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int
//--------------------------------------------------------------------+
// Application API (Single Port)
//--------------------------------------------------------------------+
static inline bool tud_hid_ready(void);
static inline uint8_t tud_hid_interface_protocol(void);
static inline uint8_t tud_hid_get_protocol(void);
static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len);
static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]);
static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal);
static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons);
TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_ready(void) {
return tud_hid_n_ready(0);
}
TU_ATTR_ALWAYS_INLINE static inline uint8_t tud_hid_interface_protocol(void) {
return tud_hid_n_interface_protocol(0);
}
TU_ATTR_ALWAYS_INLINE static inline uint8_t tud_hid_get_protocol(void) {
return tud_hid_n_get_protocol(0);
}
TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len) {
return tud_hid_n_report(0, report_id, report, len);
}
TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]) {
return tud_hid_n_keyboard_report(0, report_id, modifier, keycode);
}
TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) {
return tud_hid_n_mouse_report(0, report_id, buttons, x, y, vertical, horizontal);
}
TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_abs_mouse_report(uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) {
return tud_hid_n_abs_mouse_report(0, report_id, buttons, x, y, vertical, horizontal);
}
TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) {
return tud_hid_n_gamepad_report(0, report_id, x, y, z, rz, rx, ry, hat, buttons);
}
//--------------------------------------------------------------------+
// Callbacks (Weak is optional)
// Application Callbacks
//--------------------------------------------------------------------+
// Invoked when received GET HID REPORT DESCRIPTOR request
@@ -111,63 +128,25 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance);
uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen);
// Invoked when received SET_REPORT control request or
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
// received data on OUT endpoint (Report ID = 0, Type = OUTPUT)
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize);
// Invoked when received SET_PROTOCOL request
// protocol is either HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
TU_ATTR_WEAK void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol);
void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol);
// Invoked when received SET_IDLE request. return false will stall the request
// - Idle Rate = 0 : only send report if there is changes, i.e skip duplication
// - Idle Rate = 0 : only send report if there is changes, i.e. skip duplication
// - Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms).
TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate);
bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate);
// Invoked when sent REPORT successfully to host
// Application can use this to send the next report
// Note: For composite reports, report[0] is report ID
TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len);
void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len);
// Invoked when a transfer wasn't successful
TU_ATTR_WEAK void tud_hid_report_fail_cb(uint8_t instance, uint8_t ep_addr, uint16_t len);
//--------------------------------------------------------------------+
// Inline Functions
//--------------------------------------------------------------------+
static inline bool tud_hid_ready(void)
{
return tud_hid_n_ready(0);
}
static inline uint8_t tud_hid_interface_protocol(void)
{
return tud_hid_n_interface_protocol(0);
}
static inline uint8_t tud_hid_get_protocol(void)
{
return tud_hid_n_get_protocol(0);
}
static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len)
{
return tud_hid_n_report(0, report_id, report, len);
}
static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6])
{
return tud_hid_n_keyboard_report(0, report_id, modifier, keycode);
}
static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal)
{
return tud_hid_n_mouse_report(0, report_id, buttons, x, y, vertical, horizontal);
}
static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons)
{
return tud_hid_n_gamepad_report(0, report_id, x, y, z, rz, rx, ry, hat, buttons);
}
void tud_hid_report_failed_cb(uint8_t instance, hid_report_type_t report_type, uint8_t const* report, uint16_t xferred_bytes);
/* --------------------------------------------------------------------+
* HID Report Descriptor Template
@@ -645,9 +624,8 @@ uint16_t hidd_open (uint8_t rhport, tusb_desc_interface_t const * itf
bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
bool hidd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_HID_DEVICE_H_ */
#endif

View File

@@ -657,7 +657,9 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr,
uint8_t const data8 = desc_report[0];
TU_LOG(3, "tag = %d, type = %d, size = %d, data = ", tag, type, size);
for (uint32_t i = 0; i < size; i++) TU_LOG(3, "%02X ", desc_report[i]);
for (uint32_t i = 0; i < size; i++) {
TU_LOG(3, "%02X ", desc_report[i]);
}
TU_LOG(3, "\r\n");
switch (type) {

View File

@@ -3,6 +3,8 @@
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
* Copyright (c) 2024 Hardy Griech
* Copyright (c) 2020 Jacob Berg Potter
* Copyright (c) 2020 Peter Lawrence
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@@ -195,7 +195,6 @@
#elif TU_CHECK_MCU(OPT_MCU_STM32F4)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
#define TUP_USBIP_DWC2_TEST_MODE
// For most mcu, FS has 4, HS has 6. TODO 446/469/479 HS has 9
#define TUP_DCD_ENDPOINT_MAX 6
@@ -210,7 +209,6 @@
// MCU with on-chip HS Phy
#if defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F733xx)
#define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS
#define TUP_USBIP_DWC2_TEST_MODE
#endif
#elif TU_CHECK_MCU(OPT_MCU_STM32H7)
@@ -271,17 +269,23 @@
#define TUP_DCD_ENDPOINT_MAX 8
#elif TU_CHECK_MCU(OPT_MCU_STM32U5)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
#if defined (STM32U535xx) || defined (STM32U545xx)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
#define TUP_DCD_ENDPOINT_MAX 8
// U59x/5Ax/5Fx/5Gx are highspeed with built-in HS PHY
#if defined(STM32U595xx) || defined(STM32U599xx) || defined(STM32U5A5xx) || defined(STM32U5A9xx) || \
defined(STM32U5F7xx) || defined(STM32U5F9xx) || defined(STM32U5G7xx) || defined(STM32U5G9xx)
#define TUP_DCD_ENDPOINT_MAX 9
#define TUP_RHPORT_HIGHSPEED 1
#define TUP_USBIP_DWC2_TEST_MODE
#else
#define TUP_DCD_ENDPOINT_MAX 6
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
// U59x/5Ax/5Fx/5Gx are highspeed with built-in HS PHY
#if defined(STM32U595xx) || defined(STM32U599xx) || defined(STM32U5A5xx) || defined(STM32U5A9xx) || \
defined(STM32U5F7xx) || defined(STM32U5F9xx) || defined(STM32U5G7xx) || defined(STM32U5G9xx)
#define TUP_DCD_ENDPOINT_MAX 9
#define TUP_RHPORT_HIGHSPEED 1
#else
#define TUP_DCD_ENDPOINT_MAX 6
#endif
#endif
#elif TU_CHECK_MCU(OPT_MCU_STM32L5)
@@ -420,6 +424,15 @@
#define TUP_RHPORT_HIGHSPEED CFG_TUD_WCH_USBIP_USBHS
#define TUP_DCD_ENDPOINT_MAX (CFG_TUD_WCH_USBIP_USBHS ? 16 : 8)
#elif TU_CHECK_MCU(OPT_MCU_CH32V103)
#define TUP_USBIP_WCH_USBFS
#if !defined(CFG_TUD_WCH_USBIP_USBFS)
#define CFG_TUD_WCH_USBIP_USBFS 1
#endif
#define TUP_DCD_ENDPOINT_MAX 8
#elif TU_CHECK_MCU(OPT_MCU_CH32V20X)
// v20x support both FSDEV (USBD) and USBFS, default to FSDEV
#define TUP_USBIP_WCH_USBFS

View File

@@ -214,6 +214,15 @@ enum {
#define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2)
// USB 2.0 Spec Table 9-7: Test Mode Selectors
typedef enum {
TUSB_FEATURE_TEST_J = 1,
TUSB_FEATURE_TEST_K,
TUSB_FEATURE_TEST_SE0_NAK,
TUSB_FEATURE_TEST_PACKET,
TUSB_FEATURE_TEST_FORCE_ENABLE,
} tusb_feature_test_mode_t;
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+

View File

@@ -56,8 +56,8 @@
* #define TU_VERIFY(cond) if(cond) return false;
* #define TU_VERIFY(cond,ret) if(cond) return ret;
*
* #define TU_ASSERT(cond) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return false;}
* #define TU_ASSERT(cond,ret) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return ret;}
* #define TU_ASSERT(cond) if(cond) {TU_MESS_FAILED(); TU_BREAKPOINT(), return false;}
* #define TU_ASSERT(cond,ret) if(cond) {TU_MESS_FAILED(); TU_BREAKPOINT(), return ret;}
*------------------------------------------------------------------*/
#ifdef __cplusplus
@@ -70,9 +70,9 @@
#if CFG_TUSB_DEBUG
#include <stdio.h>
#define _MESS_FAILED() tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__)
#define TU_MESS_FAILED() tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__)
#else
#define _MESS_FAILED() do {} while (0)
#define TU_MESS_FAILED() do {} while (0)
#endif
// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7, M33. M55
@@ -119,7 +119,7 @@
*------------------------------------------------------------------*/
#define TU_ASSERT_DEFINE(_cond, _ret) \
do { \
if ( !(_cond) ) { _MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
} while(0)
#define TU_ASSERT_1ARGS(_cond) TU_ASSERT_DEFINE(_cond, false)

View File

@@ -89,14 +89,6 @@ typedef struct TU_ATTR_ALIGNED(4) {
};
} dcd_event_t;
typedef enum {
TEST_J = 1,
TEST_K,
TEST_SE0_NAK,
TEST_PACKET,
TEST_FORCE_ENABLE,
} test_mode_t;
//TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct");
//--------------------------------------------------------------------+
@@ -150,11 +142,8 @@ void dcd_disconnect(uint8_t rhport);
void dcd_sof_enable(uint8_t rhport, bool en);
#if CFG_TUD_TEST_MODE
// Check if the test mode is supported, returns true is test mode selector is supported
bool dcd_check_test_mode_support(test_mode_t test_selector) TU_ATTR_WEAK;
// Put device into a test mode (needs power cycle to quit)
void dcd_enter_test_mode(uint8_t rhport, test_mode_t test_selector) TU_ATTR_WEAK;
void dcd_enter_test_mode(uint8_t rhport, tusb_feature_test_mode_t test_selector);
#endif
//--------------------------------------------------------------------+
// Endpoint API

View File

@@ -46,13 +46,46 @@
// Weak stubs: invoked if no strong implementation is available
//--------------------------------------------------------------------+
TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) {
(void)rhport;
(void)eventid;
(void)in_isr;
(void) rhport;
(void) eventid;
(void) in_isr;
}
TU_ATTR_WEAK void tud_sof_cb(uint32_t frame_count) {
(void)frame_count;
(void) frame_count;
}
TU_ATTR_WEAK uint8_t const* tud_descriptor_bos_cb(void) {
return NULL;
}
TU_ATTR_WEAK uint8_t const* tud_descriptor_device_qualifier_cb(void) {
return NULL;
}
TU_ATTR_WEAK uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) {
(void) index;
return NULL;
}
TU_ATTR_WEAK void tud_mount_cb(void) {
}
TU_ATTR_WEAK void tud_umount_cb(void) {
}
TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en) {
(void) remote_wakeup_en;
}
TU_ATTR_WEAK void tud_resume_cb(void) {
}
TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) {
(void) rhport;
(void) stage;
(void) request;
return false;
}
TU_ATTR_WEAK bool dcd_deinit(uint8_t rhport) {
@@ -321,9 +354,17 @@ TU_ATTR_ALWAYS_INLINE static inline bool queue_event(dcd_event_t const * event,
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);
#if CFG_TUD_TEST_MODE
static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) {
TU_VERIFY(CONTROL_STAGE_ACK == stage);
uint8_t const selector = tu_u16_high(request->wIndex);
TU_LOG_USBD(" Enter Test Mode (test selector index: %d)\r\n", selector);
dcd_enter_test_mode(rhport, (tusb_feature_test_mode_t) selector);
return true;
}
#endif
// from usbd_control.c
void usbd_control_reset(void);
void usbd_control_set_request(tusb_control_request_t const *request);
@@ -549,7 +590,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) {
case DCD_EVENT_UNPLUGGED:
TU_LOG_USBD("\r\n");
usbd_reset(event.rhport);
if (tud_umount_cb) tud_umount_cb();
tud_umount_cb();
break;
case DCD_EVENT_SETUP_RECEIVED:
@@ -609,7 +650,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) {
// e.g suspend -> resume -> unplug/plug. Skip suspend/resume if not connected
if (_usbd_dev.connected) {
TU_LOG_USBD(": Remote Wakeup = %u\r\n", _usbd_dev.remote_wakeup_en);
if (tud_suspend_cb) tud_suspend_cb(_usbd_dev.remote_wakeup_en);
tud_suspend_cb(_usbd_dev.remote_wakeup_en);
} else {
TU_LOG_USBD(" Skipped\r\n");
}
@@ -618,7 +659,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) {
case DCD_EVENT_RESUME:
if (_usbd_dev.connected) {
TU_LOG_USBD("\r\n");
if (tud_resume_cb) tud_resume_cb();
tud_resume_cb();
} else {
TU_LOG_USBD(" Skipped\r\n");
}
@@ -667,8 +708,6 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
// Vendor request
if ( p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR ) {
TU_VERIFY(tud_vendor_control_xfer_cb);
usbd_control_set_complete_callback(tud_vendor_control_xfer_cb);
return tud_vendor_control_xfer_cb(rhport, CONTROL_STAGE_SETUP, p_request);
}
@@ -695,7 +734,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
}
if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) {
// Non standard request is not supported
// Non-standard request is not supported
TU_BREAKPOINT();
return false;
}
@@ -739,17 +778,23 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
_usbd_dev.speed = speed; // restore speed
}
_usbd_dev.cfg_num = cfg_num;
// Handle the new configuration and execute the corresponding callback
if ( cfg_num ) {
// switch to new configuration if not zero
TU_ASSERT( process_set_config(rhport, cfg_num) );
if ( tud_mount_cb ) tud_mount_cb();
if (!process_set_config(rhport, cfg_num)) {
TU_MESS_FAILED();
TU_BREAKPOINT();
_usbd_dev.cfg_num = 0;
return false;
}
tud_mount_cb();
} else {
if ( tud_umount_cb ) tud_umount_cb();
tud_umount_cb();
}
}
_usbd_dev.cfg_num = cfg_num;
tud_control_status(rhport, p_request);
}
break;
@@ -759,43 +804,27 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
break;
case TUSB_REQ_SET_FEATURE:
// Handle the feature selector
switch(p_request->wValue)
{
// Support for remote wakeup
switch(p_request->wValue) {
case TUSB_REQ_FEATURE_REMOTE_WAKEUP:
TU_LOG_USBD(" Enable Remote Wakeup\r\n");
// Host may enable remote wake up before suspending especially HID device
_usbd_dev.remote_wakeup_en = true;
tud_control_status(rhport, p_request);
break;
#if CFG_TUD_TEST_MODE
// Support for TEST_MODE
#if CFG_TUD_TEST_MODE
case TUSB_REQ_FEATURE_TEST_MODE: {
// Only handle the test mode if supported and valid
TU_VERIFY(dcd_enter_test_mode && dcd_check_test_mode_support && 0 == tu_u16_low(p_request->wIndex));
TU_VERIFY(0 == tu_u16_low(p_request->wIndex));
uint8_t selector = tu_u16_high(p_request->wIndex);
// Stall request if the selected test mode isn't supported
if (!dcd_check_test_mode_support((test_mode_t)selector))
{
TU_LOG_USBD(" Unsupported Test Mode (test selector index: %d)\r\n", selector);
return false;
}
// Acknowledge request
tud_control_status(rhport, p_request);
TU_LOG_USBD(" Enter Test Mode (test selector index: %d)\r\n", selector);
uint8_t const selector = tu_u16_high(p_request->wIndex);
TU_VERIFY(TUSB_FEATURE_TEST_J <= selector && selector <= TUSB_FEATURE_TEST_FORCE_ENABLE);
usbd_control_set_complete_callback(process_test_mode_cb);
tud_control_status(rhport, p_request);
break;
}
#endif /* CFG_TUD_TEST_MODE */
#endif /* CFG_TUD_TEST_MODE */
// Stall unsupported feature selector
default: return false;
@@ -1029,39 +1058,34 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
switch(desc_type)
{
case TUSB_DESC_DEVICE:
{
case TUSB_DESC_DEVICE: {
TU_LOG_USBD(" Device\r\n");
void* desc_device = (void*) (uintptr_t) tud_descriptor_device_cb();
TU_ASSERT(desc_device);
// Only response with exactly 1 Packet if: not addressed and host requested more data than device descriptor has.
// This only happens with the very first get device descriptor and EP0 size = 8 or 16.
if ((CFG_TUD_ENDPOINT0_SIZE < sizeof(tusb_desc_device_t)) && !_usbd_dev.addressed &&
((tusb_control_request_t const*) p_request)->wLength > sizeof(tusb_desc_device_t))
{
((tusb_control_request_t const*) p_request)->wLength > sizeof(tusb_desc_device_t)) {
// Hack here: we modify the request length to prevent usbd_control response with zlp
// since we are responding with 1 packet & less data than wLength.
tusb_control_request_t mod_request = *p_request;
mod_request.wLength = CFG_TUD_ENDPOINT0_SIZE;
return tud_control_xfer(rhport, &mod_request, desc_device, CFG_TUD_ENDPOINT0_SIZE);
}else
{
}else {
return tud_control_xfer(rhport, p_request, desc_device, sizeof(tusb_desc_device_t));
}
}
// break; // unreachable
case TUSB_DESC_BOS:
{
case TUSB_DESC_BOS: {
TU_LOG_USBD(" BOS\r\n");
// requested by host if USB > 2.0 ( i.e 2.1 or 3.x )
if (!tud_descriptor_bos_cb) return false;
uintptr_t desc_bos = (uintptr_t) tud_descriptor_bos_cb();
TU_ASSERT(desc_bos);
TU_VERIFY(desc_bos);
// Use offsetof to avoid pointer to the odd/misaligned address
uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_bos + offsetof(tusb_desc_bos_t, wTotalLength))) );
@@ -1071,24 +1095,20 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
// break; // unreachable
case TUSB_DESC_CONFIGURATION:
case TUSB_DESC_OTHER_SPEED_CONFIG:
{
case TUSB_DESC_OTHER_SPEED_CONFIG: {
uintptr_t desc_config;
if ( desc_type == TUSB_DESC_CONFIGURATION )
{
if ( desc_type == TUSB_DESC_CONFIGURATION ) {
TU_LOG_USBD(" Configuration[%u]\r\n", desc_index);
desc_config = (uintptr_t) tud_descriptor_configuration_cb(desc_index);
}else
{
TU_ASSERT(desc_config);
}else {
// Host only request this after getting Device Qualifier descriptor
TU_LOG_USBD(" Other Speed Configuration\r\n");
TU_VERIFY( tud_descriptor_other_speed_configuration_cb );
desc_config = (uintptr_t) tud_descriptor_other_speed_configuration_cb(desc_index);
TU_VERIFY(desc_config);
}
TU_ASSERT(desc_config);
// Use offsetof to avoid pointer to the odd/misaligned address
uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_config + offsetof(tusb_desc_configuration_t, wTotalLength))) );
@@ -1109,16 +1129,10 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
}
// break; // unreachable
case TUSB_DESC_DEVICE_QUALIFIER:
{
case TUSB_DESC_DEVICE_QUALIFIER: {
TU_LOG_USBD(" Device Qualifier\r\n");
TU_VERIFY( tud_descriptor_device_qualifier_cb );
uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb();
TU_VERIFY(desc_qualifier);
// first byte of descriptor is its size
return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_qualifier, tu_desc_len(desc_qualifier));
}
// break; // unreachable
@@ -1127,20 +1141,6 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
}
}
#if CFG_TUD_TEST_MODE
static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
{
// At this point it should already be ensured that dcd_enter_test_mode() is defined
// Only enter the test mode after the request for it has completed
TU_VERIFY(CONTROL_STAGE_ACK == stage);
dcd_enter_test_mode(rhport, (test_mode_t)tu_u16_high(request->wIndex));
return true;
}
#endif /* CFG_TUD_TEST_MODE */
//--------------------------------------------------------------------+
// DCD Event Handler
//--------------------------------------------------------------------+

View File

@@ -109,7 +109,7 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, vo
bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request);
//--------------------------------------------------------------------+
// Application Callbacks (WEAK is optional)
// Application Callbacks
//--------------------------------------------------------------------+
// Invoked when received GET DEVICE DESCRIPTOR request
@@ -126,31 +126,31 @@ uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid);
// Invoked when received GET BOS DESCRIPTOR request
// Application return pointer to descriptor
TU_ATTR_WEAK uint8_t const * tud_descriptor_bos_cb(void);
uint8_t const * tud_descriptor_bos_cb(void);
// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
// device_qualifier descriptor describes information about a high-speed capable device that would
// change if the device were operating at the other speed. If not highspeed capable stall this request.
TU_ATTR_WEAK uint8_t const* tud_descriptor_device_qualifier_cb(void);
uint8_t const* tud_descriptor_device_qualifier_cb(void);
// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
TU_ATTR_WEAK uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index);
uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index);
// Invoked when device is mounted (configured)
TU_ATTR_WEAK void tud_mount_cb(void);
void tud_mount_cb(void);
// Invoked when device is unmounted
TU_ATTR_WEAK void tud_umount_cb(void);
void tud_umount_cb(void);
// Invoked when usb bus is suspended
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en);
void tud_suspend_cb(bool remote_wakeup_en);
// Invoked when usb bus is resumed
TU_ATTR_WEAK void tud_resume_cb(void);
void tud_resume_cb(void);
// Invoked when there is a new usb event, which need to be processed by tud_task()/tud_task_ext()
void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr);
@@ -159,7 +159,7 @@ void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr);
void tud_sof_cb(uint32_t frame_count);
// Invoked when received control request with VENDOR TYPE
TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
//--------------------------------------------------------------------+
// Binary Device Object Store (BOS) Descriptor Templates

View File

@@ -1113,7 +1113,7 @@ bool tuh_interface_set(uint8_t daddr, uint8_t itf_num, uint8_t itf_alt,
TU_LOG_USBH("Set Interface %u Alternate %u\r\n", itf_num, itf_alt);
tusb_control_request_t const request = {
.bmRequestType_bit = {
.recipient = TUSB_REQ_RCPT_DEVICE,
.recipient = TUSB_REQ_RCPT_INTERFACE,
.type = TUSB_REQ_TYPE_STANDARD,
.direction = TUSB_DIR_OUT
},
@@ -1421,6 +1421,9 @@ static void process_enumeration(tuh_xfer_t* xfer) {
break;
case ENUM_GET_DEVICE_DESC: {
// Allow 2ms for address recovery time, Ref USB Spec 9.2.6.3
osal_task_delay(2);
uint8_t const new_addr = (uint8_t) tu_le16toh(xfer->setup->wValue);
usbh_device_t* new_dev = get_device(new_addr);

View File

@@ -78,7 +78,7 @@ typedef struct
// _int_set is not used with an RTOS
#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
static _type _name##_##buf[_depth];\
osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf, _OSAL_Q_NAME(_name) };
osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf, _OSAL_Q_NAME(_name) }
//--------------------------------------------------------------------+
// TASK API

View File

@@ -907,9 +907,9 @@ void tusb_hal_nrf_power_event(uint32_t event) {
USB_EVT_READY = 2
};
#if CFG_TUSB_DEBUG >= 2
#if CFG_TUSB_DEBUG >= 3
const char* const power_evt_str[] = {"Detected", "Removed", "Ready"};
TU_LOG(2, "Power USB event: %s\r\n", power_evt_str[event]);
TU_LOG(3, "Power USB event: %s\r\n", power_evt_str[event]);
#endif
switch (event) {

View File

@@ -540,7 +540,7 @@ void dcd_int_handler(uint8_t rhport)
}
if (is & USB_ISTAT_SLEEP_MASK) {
// TU_LOG2("Suspend: "); TU_LOG2_HEX(is);
// TU_LOG3("Suspend: "); TU_LOG2_HEX(is);
// Note Host usually has extra delay after bus reset (without SOF), which could falsely
// detected as Sleep event. Though usbd has debouncing logic so we are good

View File

@@ -53,6 +53,14 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_host_mode(void) {
//--------------------------------------------------------------------+
// Implementation
//--------------------------------------------------------------------+
// Provide own byte by byte memcpy as not all copies are aligned
static void unaligned_memcpy(void *dst, const void *src, size_t n) {
uint8_t *dst_byte = (uint8_t*)dst;
const uint8_t *src_byte = (const uint8_t*)src;
while (n--) {
*dst_byte++ = *src_byte++;
}
}
void rp2040_usb_init(void) {
// Reset usb controller
@@ -67,7 +75,6 @@ void rp2040_usb_init(void) {
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif
#endif
memset(usb_hw, 0, sizeof(*usb_hw));
memset(usb_dpram, 0, sizeof(*usb_dpram));
#ifdef __GNUC__
#pragma GCC diagnostic pop
@@ -125,7 +132,7 @@ static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint* ep,
if (!ep->rx) {
// Copy data from user buffer to hw buffer
memcpy(ep->hw_data_buf + buf_id * 64, ep->user_buf, buflen);
unaligned_memcpy(ep->hw_data_buf + buf_id * 64, ep->user_buf, buflen);
ep->user_buf += buflen;
// Mark as full
@@ -230,7 +237,7 @@ static uint16_t __tusb_irq_path_func(sync_ep_buffer)(struct hw_endpoint* ep, uin
// we have received AFTER we have copied it to the user buffer at the appropriate offset
assert(buf_ctrl & USB_BUF_CTRL_FULL);
memcpy(ep->user_buf, ep->hw_data_buf + buf_id * 64, xferred_bytes);
unaligned_memcpy(ep->user_buf, ep->hw_data_buf + buf_id * 64, xferred_bytes);
ep->xferred_len = (uint16_t) (ep->xferred_len + xferred_bytes);
ep->user_buf += xferred_bytes;
}

View File

@@ -37,14 +37,20 @@
* It also should work with minimal changes for any ST MCU with an "USB A"/"PCD"/"HCD" peripheral. This
* covers:
*
* F04x, F072, F078, 070x6/B 1024 byte buffer
* F04x, F072, F078, F070x6/B 1024 byte buffer
* F102, F103 512 byte buffer; no internal D+ pull-up (maybe many more changes?)
* F302xB/C, F303xB/C, F373 512 byte buffer; no internal D+ pull-up
* F302x6/8, F302xD/E2, F303xD/E 1024 byte buffer; no internal D+ pull-up
* G0 2048 byte buffer; 32-bit bus; host mode
* G4 1024 byte buffer
* H5 2048 byte buffer; 32-bit bus; host mode
* L0x2, L0x3 1024 byte buffer
* L1 512 byte buffer
* L4x2, L4x3 1024 byte buffer
* G0 2048 byte buffer
* L5 1024 byte buffer
* U0 1024 byte buffer; 32-bit bus
* U535, U545 2048 byte buffer; 32-bit bus; host mode
* WB35, WB55 1024 byte buffer
*
* To use this driver, you must:
* - If you are using a device with crystal-less USB, set up the clock recovery system (CRS)
@@ -215,24 +221,24 @@ void dcd_init(uint8_t rhport)
/* The RM mentions to use a special ordering of PDWN and FRES, but this isn't done in HAL.
* Here, the RM is followed. */
for (uint32_t i = 0; i < 200; i++) { // should be a few us
for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us
asm("NOP");
}
// Perform USB peripheral reset
USB->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN;
for (uint32_t i = 0; i < 200; i++) { // should be a few us
for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us
asm("NOP");
}
USB->CNTR &= ~USB_CNTR_PDWN;
// Wait startup time, for F042 and F070, this is <= 1 us.
for (uint32_t i = 0; i < 200; i++) { // should be a few us
for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us
asm("NOP");
}
USB->CNTR = 0; // Enable USB
#if !defined(STM32G0) && !defined(STM32H5) // BTABLE register does not exist any more on STM32G0, it is fixed to USB SRAM base address
#if !defined(STM32G0) && !defined(STM32H5) && !defined(STM32U5) // BTABLE register does not exist any more on STM32G0, it is fixed to USB SRAM base address
USB->BTABLE = DCD_STM32_BTABLE_BASE;
#endif
USB->ISTR = 0; // Clear pending interrupts
@@ -998,7 +1004,7 @@ static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, ui
srcVal++;
}
if (wNBytes) {
if (wNBytes & 0x01) {
temp1 = (uint16_t) *srcVal;
*pdwVal = temp1;
}

View File

@@ -36,11 +36,21 @@
#include "common/tusb_compiler.h"
#if CFG_TUSB_MCU == OPT_MCU_CH32V20X
#include <ch32v20x.h>
// https://github.com/openwch/ch32v307/pull/90
// https://github.com/openwch/ch32v20x/pull/12
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#endif
#elif CFG_TUSB_MCU == OPT_MCU_CH32F20X
#if CFG_TUSB_MCU == OPT_MCU_CH32F20X
#include <ch32f20x.h>
#elif CFG_TUSB_MCU == OPT_MCU_CH32V20X
#include <ch32v20x.h>
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#define FSDEV_PMA_SIZE (512u)

View File

@@ -295,18 +295,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, u
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPTX_DTOGMASK;
/* toggle first bit ? */
if((USB_EPTX_DTOG1 & (wState))!= 0U)
{
regVal ^= USB_EPTX_DTOG1;
}
/* toggle second bit ? */
if((USB_EPTX_DTOG2 & ((uint32_t)(wState)))!= 0U)
{
regVal ^= USB_EPTX_DTOG2;
}
regVal ^= wState;
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
pcd_set_endpoint(USBx, bEpIdx, regVal);
}
@@ -322,16 +311,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPRX_DTOGMASK;
/* toggle first bit ? */
if((USB_EPRX_DTOG1 & wState)!= 0U) {
regVal ^= USB_EPRX_DTOG1;
}
/* toggle second bit ? */
if((USB_EPRX_DTOG2 & wState)!= 0U) {
regVal ^= USB_EPRX_DTOG2;
}
regVal ^= wState;
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
pcd_set_endpoint(USBx, bEpIdx, regVal);
}

View File

@@ -159,9 +159,38 @@
#define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS))
#endif
#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
#include "stm32u5xx.h"
#define FSDEV_BUS_32BIT
#define FSDEV_PMA_SIZE (2048u)
#undef USB_PMAADDR
#define USB_PMAADDR USB_DRD_PMAADDR
#define USB_TypeDef USB_DRD_TypeDef
#define EP0R CHEP0R
#define USB_EP_CTR_RX USB_EP_VTRX
#define USB_EP_CTR_TX USB_EP_VTTX
#define USB_EP_T_FIELD USB_CHEP_UTYPE
#define USB_EPREG_MASK USB_CHEP_REG_MASK
#define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
#define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
#define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
#define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
#define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
#define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
#define USB_EPRX_STAT USB_CH_RX_VALID
#define USB_EPKIND_MASK USB_EP_KIND_MASK
#define USB USB_DRD_FS
#define USB_CNTR_FRES USB_CNTR_USBRST
#define USB_CNTR_RESUME USB_CNTR_L2RES
#define USB_ISTR_EP_ID USB_ISTR_IDN
#define USB_EPADDR_FIELD USB_CHEP_ADDR
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
#define USB_CNTR_FSUSP USB_CNTR_SUSPEN
#else
#error You are using an untested or unimplemented STM32 variant. Please update the driver.
// This includes L1x0, L1x1, L1x2, L4x2 and L4x3, G1x1, G1x3, and G1x4
// This includes U0
#endif
// This checks if the device has "LPM"
@@ -211,6 +240,8 @@ static const IRQn_Type fsdev_irq[] = {
#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
USB_HP_IRQn,
USB_LP_IRQn,
#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
USB_IRQn,
#else
#error Unknown arch in USB driver
#endif

View File

@@ -1195,25 +1195,13 @@ void dcd_int_handler(uint8_t rhport) {
// }
}
#if defined(TUP_USBIP_DWC2_TEST_MODE) && CFG_TUD_TEST_MODE
bool dcd_check_test_mode_support(test_mode_t test_selector) {
// Check if test mode selector is unsupported
if (TEST_FORCE_ENABLE < test_selector || TEST_J > test_selector) {
return false;
}
return true;
}
void dcd_enter_test_mode(uint8_t rhport, test_mode_t test_selector) {
// Get port address...
#if CFG_TUD_TEST_MODE
void dcd_enter_test_mode(uint8_t rhport, tusb_feature_test_mode_t test_selector) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
// Enable the test mode
dwc2->dctl = (dwc2->dctl & ~DCTL_TCTL_Msk) | (test_selector << DCTL_TCTL_Pos);
dwc2->dctl = (dwc2->dctl & ~DCTL_TCTL_Msk) | (((uint8_t) test_selector) << DCTL_TCTL_Pos);
}
#endif /* TUP_USBIP_DWC2_TEST_MODE && CFG_TUD_TEST_MODE */
#endif
#endif

View File

@@ -35,6 +35,7 @@
#include "esp_intr_alloc.h"
#include "soc/periph_defs.h"
//#include "soc/usb_periph.h"
#include "freertos/task.h"
#define DWC2_REG_BASE 0x60080000UL
#define DWC2_EP_MAX 6 // USB_OUT_EP_NUM. TODO ESP32Sx only has 5 tx fifo (5 endpoint IN)

View File

@@ -28,15 +28,79 @@
#ifndef USB_CH32_USBFS_REG_H
#define USB_CH32_USBFS_REG_H
#if CFG_TUSB_MCU == OPT_MCU_CH32V307
#include <ch32v30x.h>
#define USBHD_IRQn OTG_FS_IRQn
// https://github.com/openwch/ch32v307/pull/90
// https://github.com/openwch/ch32v20x/pull/12
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#endif
#if CFG_TUSB_MCU == OPT_MCU_CH32F20X
#include <ch32f20x.h>
#elif CFG_TUSB_MCU == OPT_MCU_CH32V103
#include <ch32v10x.h>
typedef struct
{
__IO uint8_t BASE_CTRL;
__IO uint8_t UDEV_CTRL;
__IO uint8_t INT_EN;
__IO uint8_t DEV_ADDR;
__IO uint8_t Reserve0;
__IO uint8_t MIS_ST;
__IO uint8_t INT_FG;
__IO uint8_t INT_ST;
__IO uint32_t RX_LEN;
__IO uint8_t UEP4_1_MOD;
__IO uint8_t UEP2_3_MOD;
__IO uint8_t UEP5_6_MOD;
__IO uint8_t UEP7_MOD;
__IO uint32_t UEP0_DMA;
__IO uint32_t UEP1_DMA;
__IO uint32_t UEP2_DMA;
__IO uint32_t UEP3_DMA;
__IO uint32_t UEP4_DMA;
__IO uint32_t UEP5_DMA;
__IO uint32_t UEP6_DMA;
__IO uint32_t UEP7_DMA;
__IO uint16_t UEP0_TX_LEN;
__IO uint8_t UEP0_TX_CTRL;
__IO uint8_t UEP0_RX_CTRL;
__IO uint16_t UEP1_TX_LEN;
__IO uint8_t UEP1_TX_CTRL;
__IO uint8_t UEP1_RX_CTRL;
__IO uint16_t UEP2_TX_LEN;
__IO uint8_t UEP2_TX_CTRL;
__IO uint8_t UEP2_RX_CTRL;
__IO uint16_t UEP3_TX_LEN;
__IO uint8_t UEP3_TX_CTRL;
__IO uint8_t UEP3_RX_CTRL;
__IO uint16_t UEP4_TX_LEN;
__IO uint8_t UEP4_TX_CTRL;
__IO uint8_t UEP4_RX_CTRL;
__IO uint16_t UEP5_TX_LEN;
__IO uint8_t UEP5_TX_CTRL;
__IO uint8_t UEP5_RX_CTRL;
__IO uint16_t UEP6_TX_LEN;
__IO uint8_t UEP6_TX_CTRL;
__IO uint8_t UEP6_RX_CTRL;
__IO uint16_t UEP7_TX_LEN;
__IO uint8_t UEP7_TX_CTRL;
__IO uint8_t UEP7_RX_CTRL;
__IO uint32_t Reserve1;
__IO uint32_t OTG_CR;
__IO uint32_t OTG_SR;
} USBOTG_FS_TypeDef;
#define USBOTG_FS ((USBOTG_FS_TypeDef *) 0x40023400)
#elif CFG_TUSB_MCU == OPT_MCU_CH32V20X
#include <ch32v20x.h>
#elif CFG_TUSB_MCU == OPT_MCU_CH32V307
#include <ch32v30x.h>
#define USBHD_IRQn OTG_FS_IRQn
#endif
#elif CFG_TUSB_MCU == OPT_MCU_CH32F20X
#include <ch32f20x.h>
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
// CTRL

View File

@@ -28,12 +28,24 @@
#ifndef USB_CH32_USBHS_REG_H
#define USB_CH32_USBHS_REG_H
// https://github.com/openwch/ch32v307/pull/90
// https://github.com/openwch/ch32v20x/pull/12
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#endif
#if CFG_TUSB_MCU == OPT_MCU_CH32V307
#include <ch32v30x.h>
#elif CFG_TUSB_MCU == OPT_MCU_CH32F20X
#include <ch32f20x.h>
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
/******************* GLOBAL ******************/
// USB CONTROL

View File

@@ -398,7 +398,7 @@ static void dump_str_line(uint8_t const* buf, uint16_t count) {
tu_printf(" |");
// each line is 16 bytes
for (uint16_t i = 0; i < count; i++) {
const char ch = buf[i];
int ch = buf[i];
tu_printf("%c", isprint(ch) ? ch : '.');
}
tu_printf("|\r\n");

View File

@@ -182,7 +182,7 @@
#define OPT_MCU_CH32V307 2200 ///< WCH CH32V307
#define OPT_MCU_CH32F20X 2210 ///< WCH CH32F20x
#define OPT_MCU_CH32V20X 2220 ///< WCH CH32V20X
#define OPT_MCU_CH32V103 2230 ///< WCH CH32V103
// NXP LPC MCX
#define OPT_MCU_MCXN9 2300 ///< NXP MCX N9 Series
@@ -381,7 +381,7 @@
#error "CFG_TUD_ENDPPOINT_MAX must be less than or equal to TUP_DCD_ENDPOINT_MAX"
#endif
// USB 2.0 compliance test mode support
// USB 2.0 7.1.20: compliance test mode support
#ifndef CFG_TUD_TEST_MODE
#define CFG_TUD_TEST_MODE 0
#endif

View File

@@ -63,7 +63,7 @@ typedef struct TU_ATTR_PACKED {
} xfer_complete;
};
} tcd_event_t;;
} tcd_event_t;
//--------------------------------------------------------------------+
//