From 4a52edd93b926e3783d998b55bdb0c56e52a839f Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 11 Oct 2025 16:28:45 +0200 Subject: dfu: remove transfer buffer out of USB section, since data will copy to/from use EP0 buffer. Signed-off-by: HiFiPhile --- src/class/dfu/dfu_device.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'src/class') diff --git a/src/class/dfu/dfu_device.c b/src/class/dfu/dfu_device.c index 0d2b63b57..24b037ebb 100644 --- a/src/class/dfu/dfu_device.c +++ b/src/class/dfu/dfu_device.c @@ -62,9 +62,7 @@ typedef struct { // Only a single dfu state is allowed static dfu_state_ctx_t _dfu_ctx; -CFG_TUD_MEM_SECTION static struct { - TUD_EPBUF_DEF(transfer_buf, CFG_TUD_DFU_XFER_BUFSIZE); -} _dfu_epbuf; +CFG_TUD_MEM_ALIGN uint8_t _transfer_buf[CFG_TUD_DFU_XFER_BUFSIZE]; static void reset_state(void) { _dfu_ctx.state = DFU_IDLE; @@ -283,10 +281,10 @@ bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_UPLOAD); TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE); - const uint16_t xfer_len = tud_dfu_upload_cb(_dfu_ctx.alt, request->wValue, _dfu_epbuf.transfer_buf, + const uint16_t xfer_len = tud_dfu_upload_cb(_dfu_ctx.alt, request->wValue, _transfer_buf, request->wLength); - return tud_control_xfer(rhport, request, _dfu_epbuf.transfer_buf, xfer_len); + return tud_control_xfer(rhport, request, _transfer_buf, xfer_len); } break; @@ -306,7 +304,7 @@ bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control if (request->wLength) { // Download with payload -> transition to DOWNLOAD SYNC _dfu_ctx.state = DFU_DNLOAD_SYNC; - return tud_control_xfer(rhport, request, _dfu_epbuf.transfer_buf, request->wLength); + return tud_control_xfer(rhport, request, _transfer_buf, request->wLength); } else { // Download is complete -> transition to MANIFEST SYNC _dfu_ctx.state = DFU_MANIFEST_SYNC; @@ -378,7 +376,7 @@ static bool process_download_get_status(uint8_t rhport, uint8_t stage, const tus } else if (stage == CONTROL_STAGE_ACK) { if (_dfu_ctx.flashing_in_progress) { _dfu_ctx.state = DFU_DNBUSY; - tud_dfu_download_cb(_dfu_ctx.alt, _dfu_ctx.block, _dfu_epbuf.transfer_buf, _dfu_ctx.length); + tud_dfu_download_cb(_dfu_ctx.alt, _dfu_ctx.block, _transfer_buf, _dfu_ctx.length); } else { _dfu_ctx.state = DFU_DNLOAD_IDLE; } -- cgit v1.3.1 From 032de0b0df92162aa579eda986145e3756a29a6c Mon Sep 17 00:00:00 2001 From: Tobi Date: Thu, 30 Oct 2025 12:21:21 +0100 Subject: Video Class: New callback function added which allows to generate frame data on the fly - If buffer is set to NULL, the callback will request payload data from a user function. This allows to work with dynamic content on platforms which are not able to hold a whole frame in memory. - Callback uses the same "weak" linking as other callbacks for this class. --- src/class/video/video_device.c | 18 +++++++++++++++--- src/class/video/video_device.h | 10 ++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) (limited to 'src/class') diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index 5c00cc358..00f192af6 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -214,6 +214,14 @@ TU_ATTR_WEAK int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, return VIDEO_ERROR_NONE; } +TU_ATTR_WEAK void tud_video_prepare_payload_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void* payload_buf, size_t payload_size, size_t offset) { + (void) ctl_idx; + (void) stm_idx; + (void) payload_buf; + (void) payload_size; + (void) offset; +} + //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ @@ -860,7 +868,11 @@ static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm, uint } TU_ASSERT(pkt_len >= hdr_len); uint_fast16_t data_len = pkt_len - hdr_len; - memcpy(&ep_buf[hdr_len], stm->buffer + stm->offset, data_len); + if (stm->buffer) { + memcpy(&ep_buf[hdr_len], stm->buffer + stm->offset, data_len); + } else { + tud_video_prepare_payload_cb(stm->index_vc, stm->index_vs, &ep_buf[hdr_len], data_len, stm->offset); + } stm->offset += data_len; remaining -= data_len; if (!remaining) { @@ -1235,11 +1247,11 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu TU_ASSERT(ctl_idx < CFG_TUD_VIDEO); TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING); - if (!buffer || !bufsize) return false; + if (!bufsize) return false; videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx); videod_streaming_epbuf_t *stm_epbuf = &_videod_streaming_epbuf[ctl_idx]; - if (!stm || !stm->desc.ep[0] || stm->buffer) return false; + if (!stm || !stm->desc.ep[0] || stm->bufsize) return false; if (stm->state == VS_STATE_PROBING) return false; /* Find EP address */ diff --git a/src/class/video/video_device.h b/src/class/video/video_device.h index 2b41c3bfe..b3094dd81 100644 --- a/src/class/video/video_device.h +++ b/src/class/video/video_device.h @@ -83,6 +83,16 @@ int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod); int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, video_probe_and_commit_control_t const *parameters); +/** Invoked if buffer is set to NULL (allows bufferless on the fly data generation) + * + * @param[in] ctl_idx Destination control interface index + * @param[in] stm_idx Destination streaming interface index + * @param[out] payload_buf Payload storage buffer (target buffer for requested data) + * @param[in] payload_size Size of payload_buf (requested data size) + * @param[in] offset Current byte offset relative to given bufsize from tud_video_n_frame_xfer (framesize) + * @return video_error_code_t */ +void tud_video_prepare_payload_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void* payload_buf, size_t payload_size, size_t offset); + //--------------------------------------------------------------------+ // INTERNAL USBD-CLASS DRIVER API //--------------------------------------------------------------------+ -- cgit v1.3.1 From 889cde7d4b31b30f34abc6e304445403bdf4ced4 Mon Sep 17 00:00:00 2001 From: Tobi Date: Thu, 30 Oct 2025 15:01:52 +0100 Subject: Video class: Changed pararameters of payload request to a dedicated structure in order to meet coding guideliness --- examples/device/video_capture/src/main.c | 10 +++++----- src/class/video/video_device.c | 13 ++++++++----- src/class/video/video_device.h | 12 +++++++++++- 3 files changed, 24 insertions(+), 11 deletions(-) (limited to 'src/class') diff --git a/examples/device/video_capture/src/main.c b/examples/device/video_capture/src/main.c index b01830dfe..77ffd7bef 100644 --- a/examples/device/video_capture/src/main.c +++ b/examples/device/video_capture/src/main.c @@ -131,25 +131,25 @@ void tud_resume_cb(void) { #error Demo only supports YUV2 please define CFG_EXAMPLE_VIDEO_DISABLE_MJPEG #endif -void tud_video_prepare_payload_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void* payload_buf, size_t payload_size, size_t offset) +void tud_video_prepare_payload_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, tud_video_payload_request_t* request) { static uint32_t frame_counter = 0; (void)ctl_idx; (void)stm_idx; /* Offset will be zero at the start of a new frame */ - if (!offset) frame_counter++; + if (!request->offset) frame_counter++; - for (size_t buf_pos = 0; buf_pos < payload_size; buf_pos += 2) { + for (size_t buf_pos = 0; buf_pos < request->length; buf_pos += 2) { /* Position within the current line (pixel relative) */ - int line_pos = ((offset + buf_pos)>>1) % FRAME_WIDTH; + int line_pos = ((request->offset + buf_pos)>>1) % FRAME_WIDTH; /* Choose color based on the position and change the table offset every 4 frames */ const uint8_t* color = bar_color[(line_pos/(FRAME_WIDTH / 8) + (frame_counter>>2)) % 8]; /* Copy pixel data for odd or even pixels */ - memcpy(&((uint8_t*)payload_buf)[buf_pos], &color[(line_pos & 1) ? 2 : 0], 2); + memcpy(&((uint8_t*)request->buf)[buf_pos], &color[(line_pos & 1) ? 2 : 0], 2); } } diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index 00f192af6..326f5c13d 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -214,12 +214,10 @@ TU_ATTR_WEAK int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, return VIDEO_ERROR_NONE; } -TU_ATTR_WEAK void tud_video_prepare_payload_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void* payload_buf, size_t payload_size, size_t offset) { +TU_ATTR_WEAK void tud_video_prepare_payload_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, tud_video_payload_request_t* request) { (void) ctl_idx; (void) stm_idx; - (void) payload_buf; - (void) payload_size; - (void) offset; + (void) request; } //--------------------------------------------------------------------+ @@ -871,7 +869,12 @@ static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm, uint if (stm->buffer) { memcpy(&ep_buf[hdr_len], stm->buffer + stm->offset, data_len); } else { - tud_video_prepare_payload_cb(stm->index_vc, stm->index_vs, &ep_buf[hdr_len], data_len, stm->offset); + tud_video_payload_request_t rqst = { + .buf = &ep_buf[hdr_len], + .length = data_len, + .offset = stm->offset + }; + tud_video_prepare_payload_cb(stm->index_vc, stm->index_vs, &rqst); } stm->offset += data_len; remaining -= data_len; diff --git a/src/class/video/video_device.h b/src/class/video/video_device.h index b3094dd81..f14555e4f 100644 --- a/src/class/video/video_device.h +++ b/src/class/video/video_device.h @@ -35,6 +35,16 @@ extern "C" { #endif + +//--------------------------------------------------------------------+ +// Payload request +//--------------------------------------------------------------------+ +typedef struct TU_ATTR_PACKED { + void* buf; /* Payload buffer to be filled */ + size_t length; /* Length of the requested data in bytes */ + size_t offset; /* Offset within the frame (in bytes) */ +} tud_video_payload_request_t; + //--------------------------------------------------------------------+ // Application API (Multiple Ports) // CFG_TUD_VIDEO > 1 @@ -91,7 +101,7 @@ int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, * @param[in] payload_size Size of payload_buf (requested data size) * @param[in] offset Current byte offset relative to given bufsize from tud_video_n_frame_xfer (framesize) * @return video_error_code_t */ -void tud_video_prepare_payload_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void* payload_buf, size_t payload_size, size_t offset); +void tud_video_prepare_payload_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, tud_video_payload_request_t* request); //--------------------------------------------------------------------+ // INTERNAL USBD-CLASS DRIVER API -- cgit v1.3.1 From 6b3970d5ff7547778ed5e1fc295dcfd1fbcad7e8 Mon Sep 17 00:00:00 2001 From: Tobi Date: Fri, 31 Oct 2025 17:29:58 +0100 Subject: Fixed trailing whitespaces in files (used wrong editor) --- examples/device/video_capture/src/main.c | 14 +++++++------- src/class/video/video_device.c | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src/class') diff --git a/examples/device/video_capture/src/main.c b/examples/device/video_capture/src/main.c index 77ffd7bef..ede8e3e4c 100644 --- a/examples/device/video_capture/src/main.c +++ b/examples/device/video_capture/src/main.c @@ -138,15 +138,15 @@ void tud_video_prepare_payload_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, tu (void)stm_idx; /* Offset will be zero at the start of a new frame */ - if (!request->offset) frame_counter++; + if (!request->offset) frame_counter++; for (size_t buf_pos = 0; buf_pos < request->length; buf_pos += 2) { /* Position within the current line (pixel relative) */ - int line_pos = ((request->offset + buf_pos)>>1) % FRAME_WIDTH; - + int line_pos = ((request->offset + buf_pos)>>1) % FRAME_WIDTH; + /* Choose color based on the position and change the table offset every 4 frames */ - const uint8_t* color = bar_color[(line_pos/(FRAME_WIDTH / 8) + (frame_counter>>2)) % 8]; + const uint8_t* color = bar_color[(line_pos/(FRAME_WIDTH / 8) + (frame_counter>>2)) % 8]; /* Copy pixel data for odd or even pixels */ memcpy(&((uint8_t*)request->buf)[buf_pos], &color[(line_pos & 1) ? 2 : 0], 2); @@ -233,7 +233,7 @@ static void video_send_frame(void) { tx_busy = 1; start_ms = board_millis(); #if defined(CFG_EXAMPLE_VIDEO_BUFFERLESS) - tud_video_n_frame_xfer(0, 0, NULL, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8); + tud_video_n_frame_xfer(0, 0, NULL, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8); #elif defined (CFG_EXAMPLE_VIDEO_READONLY) #if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)&frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4], @@ -254,14 +254,14 @@ static void video_send_frame(void) { tx_busy = 1; #if defined(CFG_EXAMPLE_VIDEO_BUFFERLESS) - tud_video_n_frame_xfer(0, 0, NULL, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8); + tud_video_n_frame_xfer(0, 0, NULL, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8); #elif defined(CFG_EXAMPLE_VIDEO_READONLY) #if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG) tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)&frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4], FRAME_WIDTH * FRAME_HEIGHT * 16/8); #else tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)frames[frame_num % 8].buffer, frames[frame_num % 8].size); - #endif + #endif #else fill_color_bar(frame_buffer, frame_num); tud_video_n_frame_xfer(0, 0, (void*) frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8); diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index 326f5c13d..adf8ab821 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -870,9 +870,9 @@ static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm, uint memcpy(&ep_buf[hdr_len], stm->buffer + stm->offset, data_len); } else { tud_video_payload_request_t rqst = { - .buf = &ep_buf[hdr_len], - .length = data_len, - .offset = stm->offset + .buf = &ep_buf[hdr_len], + .length = data_len, + .offset = stm->offset }; tud_video_prepare_payload_cb(stm->index_vc, stm->index_vs, &rqst); } -- cgit v1.3.1 From fc661abc18beefb57f5d1352219ed72678b59e0b Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 12 Nov 2025 10:41:58 +0700 Subject: migrate midi_device to use edpt stream API also add tud_midi_n_packet_write/read_n() --- .clang-format | 1 + src/class/midi/midi_device.c | 511 ++++++++++++++++----------------------- src/class/midi/midi_device.h | 130 ++++------ src/class/vendor/vendor_device.c | 3 +- src/common/tusb_fifo.c | 25 +- src/common/tusb_fifo.h | 38 +-- src/common/tusb_private.h | 14 +- src/tusb.c | 4 +- 8 files changed, 288 insertions(+), 438 deletions(-) (limited to 'src/class') diff --git a/.clang-format b/.clang-format index 907dd7cdd..c278fec37 100644 --- a/.clang-format +++ b/.clang-format @@ -70,6 +70,7 @@ IncludeCategories: - Regex: '.*' Priority: 3 IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentPPDirectives: BeforeHash InsertBraces: true IndentCaseLabels: true InsertNewlineAtEOF: true diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index 7dac7c4a5..f065e486a 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -36,13 +36,19 @@ #include "midi_device.h" +//--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tud_midi_rx_cb(uint8_t itf) { + (void)itf; +} + //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ typedef struct { + uint8_t rhport; uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; // For Stream read()/write() API // Messages are always 4 bytes long, queue them for reading and writing so the @@ -51,134 +57,97 @@ typedef struct { midi_driver_stream_t stream_read; /*------------- From this point, data is not cleared by bus reset -------------*/ - // FIFO - tu_fifo_t rx_ff; - tu_fifo_t tx_ff; - uint8_t rx_ff_buf[CFG_TUD_MIDI_RX_BUFSIZE]; - uint8_t tx_ff_buf[CFG_TUD_MIDI_TX_BUFSIZE]; - - #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_ff_mutex; - osal_mutex_def_t tx_ff_mutex; - #endif + // Endpoint stream + struct { + tu_edpt_stream_t tx; + tu_edpt_stream_t rx; + + uint8_t rx_ff_buf[CFG_TUD_MIDI_RX_BUFSIZE]; + uint8_t tx_ff_buf[CFG_TUD_MIDI_TX_BUFSIZE]; + } ep_stream; } midid_interface_t; -#define ITF_MEM_RESET_SIZE offsetof(midid_interface_t, rx_ff) +#define ITF_MEM_RESET_SIZE offsetof(midid_interface_t, ep_stream) + +static midid_interface_t _midid_itf[CFG_TUD_MIDI]; // Endpoint Transfer buffer -CFG_TUD_MEM_SECTION static struct { +typedef struct { TUD_EPBUF_DEF(epin, CFG_TUD_MIDI_EP_BUFSIZE); TUD_EPBUF_DEF(epout, CFG_TUD_MIDI_EP_BUFSIZE); -} _midid_epbuf[CFG_TUD_MIDI]; +} midid_epbuf_t; + +CFG_TUD_MEM_SECTION static midid_epbuf_t _midid_epbuf[CFG_TUD_MIDI]; //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -static midid_interface_t _midid_itf[CFG_TUD_MIDI]; - bool tud_midi_n_mounted (uint8_t itf) { - midid_interface_t* midi = &_midid_itf[itf]; - return midi->ep_in && midi->ep_out; -} + midid_interface_t *p_midi = &_midid_itf[itf]; -static void _prep_out_transaction(uint8_t idx) { - const uint8_t rhport = 0; - midid_interface_t* p_midi = &_midid_itf[idx]; - uint16_t available = tu_fifo_remaining(&p_midi->rx_ff); - - // Prepare for incoming data but only allow what we can store in the ring buffer. - // TODO Actually we can still carry out the transfer, keeping count of received bytes - // and slowly move it to the FIFO when read(). - // This pre-check reduces endpoint claiming - TU_VERIFY(available >= CFG_TUD_MIDI_EP_BUFSIZE, ); - - // claim endpoint - TU_VERIFY(usbd_edpt_claim(rhport, p_midi->ep_out), ); - - // fifo can be changed before endpoint is claimed - available = tu_fifo_remaining(&p_midi->rx_ff); - - if ( available >= CFG_TUD_MIDI_EP_BUFSIZE ) { - usbd_edpt_xfer(rhport, p_midi->ep_out, _midid_epbuf[idx].epout, CFG_TUD_MIDI_EP_BUFSIZE); - }else - { - // Release endpoint since we don't make any transfer - usbd_edpt_release(rhport, p_midi->ep_out); - } -} - - -//--------------------------------------------------------------------+ -// Weak stubs: invoked if no strong implementation is available -//--------------------------------------------------------------------+ -TU_ATTR_WEAK void tud_midi_rx_cb(uint8_t itf) { - (void) itf; + const bool tx_opened = tu_edpt_stream_is_opened(&p_midi->ep_stream.tx); + const bool rx_opened = tu_edpt_stream_is_opened(&p_midi->ep_stream.rx); + return tx_opened && rx_opened; } //--------------------------------------------------------------------+ // READ API //--------------------------------------------------------------------+ -uint32_t tud_midi_n_available(uint8_t itf, uint8_t cable_num) -{ +uint32_t tud_midi_n_available(uint8_t itf, uint8_t cable_num) { (void) cable_num; - - midid_interface_t* midi = &_midid_itf[itf]; - const midi_driver_stream_t* stream = &midi->stream_read; + const midid_interface_t *p_midi = &_midid_itf[itf]; + const midi_driver_stream_t *stream = &p_midi->stream_read; + const tu_edpt_stream_t *ep_str = &p_midi->ep_stream.rx; // when using with packet API stream total & index are both zero - return tu_fifo_count(&midi->rx_ff) + (uint8_t) (stream->total - stream->index); + return tu_edpt_stream_read_available(ep_str) + (uint8_t)(stream->total - stream->index); } -uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize) -{ +uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void *buffer, uint32_t bufsize) { (void) cable_num; - TU_VERIFY(bufsize, 0); - - uint8_t* buf8 = (uint8_t*) buffer; + TU_VERIFY(buffer != NULL && bufsize > 0, 0); - midid_interface_t* midi = &_midid_itf[itf]; - midi_driver_stream_t* stream = &midi->stream_read; + uint8_t *buf8 = (uint8_t *)buffer; + midid_interface_t *p_midi = &_midid_itf[itf]; + midi_driver_stream_t *stream = &p_midi->stream_read; uint32_t total_read = 0; - while( bufsize ) - { + while (bufsize > 0) { // Get new packet from fifo, then set packet expected bytes - if ( stream->total == 0 ) - { - // return if there is no more data from fifo - if ( !tud_midi_n_packet_read(itf, stream->buffer) ) return total_read; + if (stream->total == 0) { + if (!tud_midi_n_packet_read(itf, stream->buffer)) { + return total_read; // return if there is no more data from fifo + } - uint8_t const code_index = stream->buffer[0] & 0x0f; + const uint8_t code_index = stream->buffer[0] & 0x0f; // MIDI 1.0 Table 4-1: Code Index Number Classifications - switch(code_index) - { + switch (code_index) { case MIDI_CIN_MISC: case MIDI_CIN_CABLE_EVENT: // These are reserved and unused, possibly issue somewhere, skip this packet return 0; - break; case MIDI_CIN_SYSEX_END_1BYTE: case MIDI_CIN_1BYTE_DATA: stream->total = 1; - break; + break; case MIDI_CIN_SYSCOM_2BYTE : case MIDI_CIN_SYSEX_END_2BYTE : case MIDI_CIN_PROGRAM_CHANGE : case MIDI_CIN_CHANNEL_PRESSURE : stream->total = 2; - break; + break; default: stream->total = 3; - break; + break; } } // Copy data up to bufsize - uint8_t const count = (uint8_t) tu_min32(stream->total - stream->index, bufsize); + const uint8_t count = (uint8_t)tu_min32((uint32_t)(stream->total - stream->index), bufsize); // Skip the header (1st byte) in the buffer TU_VERIFY(0 == tu_memcpy_s(buf8, bufsize, stream->buffer + 1 + stream->index, count)); @@ -189,8 +158,7 @@ uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, ui bufsize -= count; // complete current event packet, reset stream - if ( stream->total == stream->index ) - { + if (stream->total == stream->index) { stream->index = 0; stream->total = 0; } @@ -199,150 +167,107 @@ uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, ui return total_read; } -bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]) -{ - midid_interface_t* midi = &_midid_itf[itf]; - TU_VERIFY(midi->ep_out); +bool tud_midi_n_packet_read(uint8_t itf, uint8_t packet[4]) { + midid_interface_t *p_midi = &_midid_itf[itf]; + tu_edpt_stream_t *ep_str = &p_midi->ep_stream.rx; + TU_VERIFY(tu_edpt_stream_is_opened(ep_str)); + return 4 == tu_edpt_stream_read(p_midi->rhport, ep_str, packet, 4); +} + +uint32_t tud_midi_n_packet_read_n(uint8_t itf, uint8_t packets[], uint32_t max_packets) { + midid_interface_t *p_midi = &_midid_itf[itf]; + tu_edpt_stream_t *ep_str = &p_midi->ep_stream.rx; + TU_VERIFY(tu_edpt_stream_is_opened(ep_str), 0); - const uint32_t num_read = tu_fifo_read_n(&midi->rx_ff, packet, 4); - _prep_out_transaction(itf); - return (num_read == 4); + const uint32_t num_read = tu_edpt_stream_read(p_midi->rhport, ep_str, packets, 4u * max_packets); + return num_read >> 2u; } //--------------------------------------------------------------------+ // WRITE API //--------------------------------------------------------------------+ - -static uint32_t write_flush(uint8_t idx) { - midid_interface_t* midi = &_midid_itf[idx]; - - if (!tu_fifo_count(&midi->tx_ff)) { - return 0; // No data to send - } - - const uint8_t rhport = 0; - - // skip if previous transfer not complete - TU_VERIFY( usbd_edpt_claim(rhport, midi->ep_in), 0 ); - - uint16_t count = tu_fifo_read_n(&midi->tx_ff, _midid_epbuf[idx].epin, CFG_TUD_MIDI_EP_BUFSIZE); - - if (count) { - TU_ASSERT( usbd_edpt_xfer(rhport, midi->ep_in, _midid_epbuf[idx].epin, count), 0 ); - return count; - }else { - // Release endpoint since we don't make any transfer - usbd_edpt_release(rhport, midi->ep_in); - return 0; - } -} - -uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, const uint8_t* buffer, uint32_t bufsize) -{ - midid_interface_t* midi = &_midid_itf[itf]; - TU_VERIFY(midi->ep_in, 0); - - midi_driver_stream_t* stream = &midi->stream_write; +uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, const uint8_t *buffer, uint32_t bufsize) { + midid_interface_t *p_midi = &_midid_itf[itf]; + midi_driver_stream_t *stream = &p_midi->stream_write; + tu_edpt_stream_t *ep_str = &p_midi->ep_stream.tx; + TU_VERIFY(tu_edpt_stream_is_opened(ep_str), 0); uint32_t i = 0; - while ( (i < bufsize) && (tu_fifo_remaining(&midi->tx_ff) >= 4) ) - { + while (i < bufsize) { + if (tu_edpt_stream_write_available(p_midi->rhport, ep_str) < 4) { + break; + } + const uint8_t data = buffer[i]; i++; - if ( stream->index == 0 ) - { + if (stream->index == 0) { //------------- New event packet -------------// const uint8_t msg = data >> 4; - stream->index = 2; + stream->index = 2; stream->buffer[1] = data; // Check to see if we're still in a SysEx transmit. - if ( ((stream->buffer[0]) & 0xF) == MIDI_CIN_SYSEX_START ) - { - if ( data == MIDI_STATUS_SYSEX_END ) - { - stream->buffer[0] = (uint8_t) ((cable_num << 4) | MIDI_CIN_SYSEX_END_1BYTE); - stream->total = 2; - } - else - { + if (((stream->buffer[0]) & 0xF) == MIDI_CIN_SYSEX_START) { + if (data == MIDI_STATUS_SYSEX_END) { + stream->buffer[0] = (uint8_t)((cable_num << 4) | MIDI_CIN_SYSEX_END_1BYTE); + stream->total = 2; + } else { stream->total = 4; } - } - else if ( (msg >= 0x8 && msg <= 0xB) || msg == 0xE ) - { + } else if ((msg >= 0x8 && msg <= 0xB) || msg == 0xE) { // Channel Voice Messages - stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg); - stream->total = 4; - } - else if ( msg == 0xC || msg == 0xD) - { + stream->buffer[0] = (uint8_t)((cable_num << 4) | msg); + stream->total = 4; + } else if (msg == 0xC || msg == 0xD) { // Channel Voice Messages, two-byte variants (Program Change and Channel Pressure) - stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg); - stream->total = 3; - } - else if ( msg == 0xf ) - { + stream->buffer[0] = (uint8_t)((cable_num << 4) | msg); + stream->total = 3; + } else if (msg == 0xf) { // System message - if ( data == MIDI_STATUS_SYSEX_START ) - { + if (data == MIDI_STATUS_SYSEX_START) { stream->buffer[0] = MIDI_CIN_SYSEX_START; - stream->total = 4; - } - else if ( data == MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME || data == MIDI_STATUS_SYSCOM_SONG_SELECT ) - { + stream->total = 4; + } else if (data == MIDI_STATUS_SYSCOM_TIME_CODE_QUARTER_FRAME || data == MIDI_STATUS_SYSCOM_SONG_SELECT) { stream->buffer[0] = MIDI_CIN_SYSCOM_2BYTE; - stream->total = 3; - } - else if ( data == MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER ) - { + stream->total = 3; + } else if (data == MIDI_STATUS_SYSCOM_SONG_POSITION_POINTER) { stream->buffer[0] = MIDI_CIN_SYSCOM_3BYTE; - stream->total = 4; - } - else - { + stream->total = 4; + } else { stream->buffer[0] = MIDI_CIN_SYSEX_END_1BYTE; - stream->total = 2; + stream->total = 2; } stream->buffer[0] |= (uint8_t)(cable_num << 4); - } - else - { + } else { // Pack individual bytes if we don't support packing them into words. - stream->buffer[0] = (uint8_t) (cable_num << 4 | 0xf); + stream->buffer[0] = (uint8_t)(cable_num << 4 | 0xf); stream->buffer[2] = 0; stream->buffer[3] = 0; - stream->index = 2; - stream->total = 2; + stream->total = 2; // index already set to 2 } - } - else - { + } else { //------------- On-going (buffering) packet -------------// - TU_ASSERT(stream->index < 4, i); stream->buffer[stream->index] = data; stream->index++; // See if this byte ends a SysEx. - if ( (stream->buffer[0] & 0xF) == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END ) - { - stream->buffer[0] = (uint8_t) ((cable_num << 4) | (MIDI_CIN_SYSEX_START + (stream->index - 1))); - stream->total = stream->index; + if ((stream->buffer[0] & 0xF) == MIDI_CIN_SYSEX_START && data == MIDI_STATUS_SYSEX_END) { + stream->buffer[0] = (uint8_t)((cable_num << 4) | (MIDI_CIN_SYSEX_START + (stream->index - 1))); + stream->total = stream->index; } } // Send out packet - if ( stream->index == stream->total ) - { + if (stream->index == stream->total) { // zeroes unused bytes for (uint8_t idx = stream->total; idx < 4; idx++) { stream->buffer[idx] = 0; } - const uint16_t count = tu_fifo_write_n(&midi->tx_ff, stream->buffer, 4); + const uint32_t count = tu_edpt_stream_write(p_midi->rhport, ep_str, stream->buffer, 4); // complete current event packet, reset stream stream->index = stream->total = 0; @@ -352,25 +277,37 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, const uint8_t* } } - write_flush(itf); + (void)tu_edpt_stream_write_xfer(p_midi->rhport, ep_str); return i; } bool tud_midi_n_packet_write (uint8_t itf, const uint8_t packet[4]) { - midid_interface_t* midi = &_midid_itf[itf]; - TU_VERIFY(midi->ep_in); + midid_interface_t *p_midi = &_midid_itf[itf]; + tu_edpt_stream_t *ep_str = &p_midi->ep_stream.tx; + TU_VERIFY(tu_edpt_stream_is_opened(ep_str)); - if (tu_fifo_remaining(&midi->tx_ff) < 4) { - return false; - } - - tu_fifo_write_n(&midi->tx_ff, packet, 4); - write_flush(itf); + TU_VERIFY(tu_edpt_stream_write_available(p_midi->rhport, ep_str) >= 4); + TU_VERIFY(tu_edpt_stream_write(p_midi->rhport, ep_str, packet, 4) > 0); + (void)tu_edpt_stream_write_xfer(p_midi->rhport, ep_str); return true; } +uint32_t tud_midi_n_packet_write_n(uint8_t itf, const uint8_t packets[], uint32_t n_packets) { + midid_interface_t *p_midi = &_midid_itf[itf]; + tu_edpt_stream_t *ep_str = &p_midi->ep_stream.tx; + TU_VERIFY(tu_edpt_stream_is_opened(ep_str), 0); + + uint32_t n_bytes = tu_edpt_stream_write_available(p_midi->rhport, ep_str); + n_bytes = tu_min32(tu_align4(n_bytes), n_packets << 2u); + + const uint32_t n_write = tu_edpt_stream_write(p_midi->rhport, ep_str, packets, n_bytes); + (void)tu_edpt_stream_write_xfer(p_midi->rhport, ep_str); + + return n_write >> 2u; +} + //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ @@ -378,72 +315,64 @@ void midid_init(void) { tu_memclr(_midid_itf, sizeof(_midid_itf)); for (uint8_t i = 0; i < CFG_TUD_MIDI; i++) { - midid_interface_t* midi = &_midid_itf[i]; - - // config fifo - tu_fifo_config(&midi->rx_ff, midi->rx_ff_buf, CFG_TUD_MIDI_RX_BUFSIZE, 1, false); // true, true - tu_fifo_config(&midi->tx_ff, midi->tx_ff_buf, CFG_TUD_MIDI_TX_BUFSIZE, 1, false); // OBVS. + midid_interface_t *p_midi = &_midid_itf[i]; + midid_epbuf_t *p_epbuf = &_midid_epbuf[i]; - #if CFG_FIFO_MUTEX - osal_mutex_t mutex_rd = osal_mutex_create(&midi->rx_ff_mutex); - osal_mutex_t mutex_wr = osal_mutex_create(&midi->tx_ff_mutex); - TU_ASSERT(mutex_wr != NULL && mutex_wr != NULL, ); + tu_edpt_stream_init( + &p_midi->ep_stream.rx, false, false, false, p_midi->ep_stream.rx_ff_buf, CFG_TUD_MIDI_RX_BUFSIZE, + p_epbuf->epout, CFG_TUD_MIDI_EP_BUFSIZE); - tu_fifo_config_mutex(&midi->rx_ff, NULL, mutex_rd); - tu_fifo_config_mutex(&midi->tx_ff, mutex_wr, NULL); - #endif + tu_edpt_stream_init( + &p_midi->ep_stream.tx, false, true, false, p_midi->ep_stream.tx_ff_buf, CFG_TUD_MIDI_TX_BUFSIZE, p_epbuf->epin, + CFG_TUD_MIDI_EP_BUFSIZE); } } bool midid_deinit(void) { - #if CFG_FIFO_MUTEX - for(uint8_t i=0; irx_ff.mutex_rd; - osal_mutex_t mutex_wr = midi->tx_ff.mutex_wr; - - if (mutex_rd) { - osal_mutex_delete(mutex_rd); - tu_fifo_config_mutex(&midi->rx_ff, NULL, NULL); - } - - if (mutex_wr) { - osal_mutex_delete(mutex_wr); - tu_fifo_config_mutex(&midi->tx_ff, NULL, NULL); - } + for (uint8_t i = 0; i < CFG_TUD_MIDI; i++) { + midid_interface_t *p_midi = &_midid_itf[i]; + tu_edpt_stream_deinit(&p_midi->ep_stream.rx); + tu_edpt_stream_deinit(&p_midi->ep_stream.tx); } - #endif - return true; } -void midid_reset(uint8_t rhport) -{ - (void) rhport; +void midid_reset(uint8_t rhport) { + (void)rhport; + for (uint8_t i = 0; i < CFG_TUD_MIDI; i++) { + midid_interface_t *p_midi = &_midid_itf[i]; + tu_memclr(p_midi, ITF_MEM_RESET_SIZE); + + tu_edpt_stream_clear(&p_midi->ep_stream.rx); + tu_edpt_stream_close(&p_midi->ep_stream.rx); - for(uint8_t i=0; irx_ff); - tu_fifo_clear(&midi->tx_ff); + tu_edpt_stream_clear(&p_midi->ep_stream.tx); + tu_edpt_stream_close(&p_midi->ep_stream.tx); } } -uint16_t midid_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uint16_t max_len) { - uint16_t drv_len = 0; - uint8_t const * p_desc = (uint8_t const *)desc_itf; +TU_ATTR_ALWAYS_INLINE static inline uint8_t find_midi_itf(uint8_t ep_addr) { + for (uint8_t idx = 0; idx < CFG_TUD_MIDI; idx++) { + const midid_interface_t *p_midi = &_midid_itf[idx]; + if (ep_addr == p_midi->ep_stream.rx.ep_addr || ep_addr == p_midi->ep_stream.tx.ep_addr) { + return idx; + } + } + return TUSB_INDEX_INVALID_8; +} + +uint16_t midid_open(uint8_t rhport, const tusb_desc_interface_t *desc_itf, uint16_t max_len) { + const uint8_t *p_desc = (const uint8_t *)desc_itf; + const uint8_t *desc_end = p_desc + max_len; // 1st Interface is Audio Control v1 (optional) if (TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass && AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass && AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_itf->bInterfaceProtocol) { - drv_len = tu_desc_len(desc_itf); p_desc = tu_desc_next(desc_itf); // Skip Class Specific descriptors - 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); + while (tu_desc_in_bounds(p_desc, desc_end) && TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc)) { + p_desc = tu_desc_next(p_desc); } } @@ -451,59 +380,44 @@ uint16_t midid_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uint1 TU_VERIFY(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); const tusb_desc_interface_t* desc_midi = (const tusb_desc_interface_t*) p_desc; - TU_VERIFY(TUSB_CLASS_AUDIO == desc_midi->bInterfaceClass && - AUDIO_SUBCLASS_MIDI_STREAMING == desc_midi->bInterfaceSubClass && - AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_midi->bInterfaceProtocol, 0); + TU_VERIFY(TUSB_CLASS_AUDIO == desc_midi->bInterfaceClass && + AUDIO_SUBCLASS_MIDI_STREAMING == desc_midi->bInterfaceSubClass && + AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_midi->bInterfaceProtocol, + 0); - // Find available interface - midid_interface_t * p_midi = NULL; - uint8_t idx; - for(idx=0; idxrhport = rhport; p_midi->itf_num = desc_midi->bInterfaceNumber; (void) p_midi->itf_num; - // next descriptor - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); + p_desc = tu_desc_next(p_desc); // Find and open endpoint descriptors - uint8_t found_endpoints = 0; - while ( (found_endpoints < desc_midi->bNumEndpoints) && (drv_len <= max_len) ) - { - if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) - { - TU_ASSERT(usbd_edpt_open(rhport, (const tusb_desc_endpoint_t*) p_desc), 0); - uint8_t ep_addr = ((const tusb_desc_endpoint_t*) p_desc)->bEndpointAddress; - - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) - { - p_midi->ep_in = ep_addr; + uint8_t found_ep = 0; + while ((found_ep < desc_midi->bNumEndpoints) && tu_desc_in_bounds(p_desc, desc_end)) { + if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) { + const tusb_desc_endpoint_t *desc_ep = (const tusb_desc_endpoint_t *)p_desc; + TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); + const uint8_t ep_addr = ((const tusb_desc_endpoint_t *)p_desc)->bEndpointAddress; + + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { + tu_edpt_stream_open(&p_midi->ep_stream.tx, desc_ep); } else { - p_midi->ep_out = ep_addr; + tu_edpt_stream_open(&p_midi->ep_stream.rx, desc_ep); + TU_ASSERT(tu_edpt_stream_read_xfer(rhport, &p_midi->ep_stream.rx) > 0, 0); // prepare to receive data } - // Class Specific MIDI Stream endpoint descriptor - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - - found_endpoints += 1; + p_desc = tu_desc_next(p_desc); // skip CS Endpoint descriptor + found_ep++; } - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); + p_desc = tu_desc_next(p_desc); } - // Prepare for incoming data - _prep_out_transaction(idx); - - return drv_len; + return (uint16_t)(p_desc - (const uint8_t *)desc_itf); } // Invoked when a control transfer occurred on an interface of this class @@ -514,44 +428,31 @@ bool midid_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_req return false; // driver doesn't support any request yet } -bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void) result; - (void) rhport; - - uint8_t idx; - midid_interface_t* p_midi; +bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { + (void)result; - // Identify which interface to use - for (idx = 0; idx < CFG_TUD_MIDI; idx++) { - p_midi = &_midid_itf[idx]; - if ((ep_addr == p_midi->ep_out) || (ep_addr == p_midi->ep_in)) { - break; - } - } + uint8_t idx = find_midi_itf(ep_addr); TU_ASSERT(idx < CFG_TUD_MIDI); + midid_interface_t *p_midi = &_midid_itf[idx]; - // receive new data - if (ep_addr == p_midi->ep_out) { - tu_fifo_write_n(&p_midi->rx_ff, _midid_epbuf[idx].epout, (uint16_t)xferred_bytes); - - // invoke receive callback if available - tud_midi_rx_cb(idx); - - // prepare for next - // TODO for now ep_out is not used by public API therefore there is no race condition, - // and does not need to claim like ep_in - _prep_out_transaction(idx); - } else if (ep_addr == p_midi->ep_in) { - if (0 == write_flush(idx)) { - // If there is no data left, a ZLP should be sent if - // xferred_bytes is multiple of EP size and not zero - if (!tu_fifo_count(&p_midi->tx_ff) && xferred_bytes && (0 == (xferred_bytes % CFG_TUD_MIDI_EP_BUFSIZE))) { - if (usbd_edpt_claim(rhport, p_midi->ep_in)) { - usbd_edpt_xfer(rhport, p_midi->ep_in, NULL, 0); - } - } + tu_edpt_stream_t *ep_st_rx = &p_midi->ep_stream.rx; + tu_edpt_stream_t *ep_st_tx = &p_midi->ep_stream.tx; + + if (ep_addr == ep_st_rx->ep_addr) { + // Received new data: put into stream's fifo + if (result == XFER_RESULT_SUCCESS) { + tu_edpt_stream_read_xfer_complete(ep_st_rx, xferred_bytes); + tud_midi_rx_cb(idx); // invoke callback } + tu_edpt_stream_read_xfer(rhport, ep_st_rx); // prepare for next data + } else if (ep_addr == ep_st_tx->ep_addr && result == XFER_RESULT_SUCCESS) { + // sent complete: try to send more if possible + if (0 == tu_edpt_stream_write_xfer(rhport, ep_st_tx)) { + // If there is no data left, a ZLP should be sent if needed + (void)tu_edpt_stream_write_zlp_if_needed(rhport, ep_st_tx, xferred_bytes); + } + } else { + return false; } return true; diff --git a/src/class/midi/midi_device.h b/src/class/midi/midi_device.h index d23516cec..ddbc2f9f0 100644 --- a/src/class/midi/midi_device.h +++ b/src/class/midi/midi_device.h @@ -36,21 +36,21 @@ #if !defined(CFG_TUD_MIDI_EP_BUFSIZE) && defined(CFG_TUD_MIDI_EPSIZE) #warning CFG_TUD_MIDI_EPSIZE is renamed to CFG_TUD_MIDI_EP_BUFSIZE, please update to use the new name - #define CFG_TUD_MIDI_EP_BUFSIZE CFG_TUD_MIDI_EPSIZE + #define CFG_TUD_MIDI_EP_BUFSIZE CFG_TUD_MIDI_EPSIZE #endif #ifndef CFG_TUD_MIDI_EP_BUFSIZE - #define CFG_TUD_MIDI_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) + #define CFG_TUD_MIDI_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) #endif #ifdef __cplusplus - extern "C" { +extern "C" { #endif -/** \addtogroup MIDI_Serial Serial - * @{ - * \defgroup MIDI_Serial_Device Device - * @{ */ +//--------------------------------------------------------------------+ +// Application Callback API (optional) +//--------------------------------------------------------------------+ +void tud_midi_rx_cb(uint8_t itf); //--------------------------------------------------------------------+ // Application API (Multiple Interfaces) @@ -58,117 +58,77 @@ //--------------------------------------------------------------------+ // Check if midi interface is mounted -bool tud_midi_n_mounted (uint8_t itf); +bool tud_midi_n_mounted(uint8_t itf); // Get the number of bytes available for reading -uint32_t tud_midi_n_available (uint8_t itf, uint8_t cable_num); - -// Read byte stream (legacy) -uint32_t tud_midi_n_stream_read (uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize); - -// Write byte Stream (legacy) -uint32_t tud_midi_n_stream_write (uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); - -// Read event packet (4 bytes) -bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4]); - -// Write event packet (4 bytes) -bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4]); +uint32_t tud_midi_n_available(uint8_t itf, uint8_t cable_num); -//--------------------------------------------------------------------+ -// Application API (Single Interface) -//--------------------------------------------------------------------+ -static inline bool tud_midi_mounted (void); -static inline uint32_t tud_midi_available (void); - -static inline uint32_t tud_midi_stream_read (void* buffer, uint32_t bufsize); -static inline uint32_t tud_midi_stream_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize); - -static inline bool tud_midi_packet_read (uint8_t packet[4]); -static inline bool tud_midi_packet_write (uint8_t const packet[4]); - -//------------- Deprecated API name -------------// -// TODO remove after 0.10.0 release - -TU_ATTR_DEPRECATED("tud_midi_read() is renamed to tud_midi_stream_read()") -static inline uint32_t tud_midi_read (void* buffer, uint32_t bufsize) -{ - return tud_midi_stream_read(buffer, bufsize); -} +// Read byte stream (legacy) +uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void *buffer, uint32_t bufsize); -TU_ATTR_DEPRECATED("tud_midi_write() is renamed to tud_midi_stream_write()") -static inline uint32_t tud_midi_write(uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) -{ - return tud_midi_stream_write(cable_num, buffer, bufsize); -} +// Write byte Stream (legacy) +uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, const uint8_t *buffer, uint32_t bufsize); +// Read an event 4-byte packet +bool tud_midi_n_packet_read(uint8_t itf, uint8_t packet[4]); -TU_ATTR_DEPRECATED("tud_midi_send() is renamed to tud_midi_packet_write()") -static inline bool tud_midi_send(uint8_t packet[4]) -{ - return tud_midi_packet_write(packet); -} +// Read multiple event packets, return number of read packets +uint32_t tud_midi_n_packet_read_n(uint8_t itf, uint8_t packets[], uint32_t max_packets); -TU_ATTR_DEPRECATED("tud_midi_receive() is renamed to tud_midi_packet_read()") -static inline bool tud_midi_receive(uint8_t packet[4]) -{ - return tud_midi_packet_read(packet); -} +// Write an event 4-byte packet +bool tud_midi_n_packet_write(uint8_t itf, const uint8_t packet[4]); -//--------------------------------------------------------------------+ -// Application Callback API (optional) -//--------------------------------------------------------------------+ -void tud_midi_rx_cb(uint8_t itf); +// Write multiple event packets, return number of written packets +uint32_t tud_midi_n_packet_write_n(uint8_t itf, const uint8_t packets[], uint32_t n_packets); //--------------------------------------------------------------------+ -// Inline Functions +// Application API (Single Interface) //--------------------------------------------------------------------+ - -static inline bool tud_midi_mounted (void) -{ +TU_ATTR_ALWAYS_INLINE static inline bool tud_midi_mounted(void) { return tud_midi_n_mounted(0); } -static inline uint32_t tud_midi_available (void) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_midi_available(void) { return tud_midi_n_available(0, 0); } -static inline uint32_t tud_midi_stream_read (void* buffer, uint32_t bufsize) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_midi_stream_read(void *buffer, uint32_t bufsize) { return tud_midi_n_stream_read(0, 0, buffer, bufsize); } -static inline uint32_t tud_midi_stream_write (uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t +tud_midi_stream_write(uint8_t cable_num, const uint8_t *buffer, uint32_t bufsize) { return tud_midi_n_stream_write(0, cable_num, buffer, bufsize); } -static inline bool tud_midi_packet_read (uint8_t packet[4]) -{ +TU_ATTR_ALWAYS_INLINE static inline bool tud_midi_packet_read(uint8_t packet[4]) { return tud_midi_n_packet_read(0, packet); } -static inline bool tud_midi_packet_write (uint8_t const packet[4]) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_midi_packet_read_n(uint8_t packets[], uint32_t max_packets) { + return tud_midi_n_packet_read_n(0, packets, max_packets); +} + +TU_ATTR_ALWAYS_INLINE static inline bool tud_midi_packet_write(const uint8_t packet[4]) { return tud_midi_n_packet_write(0, packet); } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_midi_packet_write_n(const uint8_t packets[], uint32_t n_packets) { + return tud_midi_n_packet_write_n(0, packets, n_packets); +} + //--------------------------------------------------------------------+ // Internal Class Driver API //--------------------------------------------------------------------+ -void midid_init (void); -bool midid_deinit (void); -void midid_reset (uint8_t rhport); -uint16_t midid_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -bool midid_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); -bool midid_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); +void midid_init(void); +bool midid_deinit(void); +void midid_reset(uint8_t rhport); +uint16_t midid_open(uint8_t rhport, const tusb_desc_interface_t *itf_desc, uint16_t max_len); +bool midid_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_request_t *request); +bool midid_xfer_cb(uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); #ifdef __cplusplus - } +} #endif -#endif /* TUSB_MIDI_DEVICE_H_ */ - -/** @} */ -/** @} */ +#endif diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index 27724b194..c916ebe47 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -202,8 +202,9 @@ void vendord_reset(uint8_t rhport) { vendord_interface_t* p_itf = &_vendord_itf[i]; tu_memclr(p_itf, ITF_MEM_RESET_SIZE); tu_edpt_stream_clear(&p_itf->rx.stream); - tu_edpt_stream_clear(&p_itf->tx.stream); tu_edpt_stream_close(&p_itf->rx.stream); + + tu_edpt_stream_clear(&p_itf->tx.stream); tu_edpt_stream_close(&p_itf->tx.stream); } } diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 419046b8b..5c9e586fb 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -551,27 +551,10 @@ static uint16_t _tu_fifo_read_n(tu_fifo_t *f, void *buffer, uint16_t n, tu_fifo_ @returns Number of items in FIFO */ /******************************************************************************/ -uint16_t tu_fifo_count(tu_fifo_t *f) { +uint16_t tu_fifo_count(const tu_fifo_t *f) { return tu_min16(_ff_count(f->depth, f->wr_idx, f->rd_idx), f->depth); } -/******************************************************************************/ -/*! - @brief Check if FIFO is empty. - - As this function only reads the read and write pointers once, this function is - reentrant and thus thread and ISR save without any mutexes. - - @param[in] f - Pointer to the FIFO buffer to manipulate - - @returns Number of items in FIFO - */ -/******************************************************************************/ -bool tu_fifo_empty(tu_fifo_t *f) { - return f->wr_idx == f->rd_idx; -} - /******************************************************************************/ /*! @brief Check if FIFO is full. @@ -585,7 +568,7 @@ bool tu_fifo_empty(tu_fifo_t *f) { @returns Number of items in FIFO */ /******************************************************************************/ -bool tu_fifo_full(tu_fifo_t *f) { +bool tu_fifo_full(const tu_fifo_t *f) { return _ff_count(f->depth, f->wr_idx, f->rd_idx) >= f->depth; } @@ -602,7 +585,7 @@ bool tu_fifo_full(tu_fifo_t *f) { @returns Number of items in FIFO */ /******************************************************************************/ -uint16_t tu_fifo_remaining(tu_fifo_t *f) { +uint16_t tu_fifo_remaining(const tu_fifo_t *f) { return _ff_remaining(f->depth, f->wr_idx, f->rd_idx); } @@ -627,7 +610,7 @@ uint16_t tu_fifo_remaining(tu_fifo_t *f) { @returns True if overflow happened */ /******************************************************************************/ -bool tu_fifo_overflowed(tu_fifo_t *f) { +bool tu_fifo_overflowed(const tu_fifo_t *f) { return _ff_count(f->depth, f->wr_idx, f->rd_idx) > f->depth; } diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 0f4ba00d8..9d8b864e9 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -155,33 +155,35 @@ void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_m #define tu_fifo_config_mutex(_f, _wr_mutex, _rd_mutex) #endif -bool tu_fifo_write (tu_fifo_t* f, void const * data); -uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * data, uint16_t n); -#ifdef TUP_MEM_CONST_ADDR -uint16_t tu_fifo_write_n_const_addr_full_words (tu_fifo_t* f, const void * data, uint16_t n); -#endif +bool tu_fifo_write(tu_fifo_t *f, void const *data); +uint16_t tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n); + +bool tu_fifo_read(tu_fifo_t *f, void *buffer); +uint16_t tu_fifo_read_n(tu_fifo_t *f, void *buffer, uint16_t n); -bool tu_fifo_read (tu_fifo_t* f, void * buffer); -uint16_t tu_fifo_read_n (tu_fifo_t* f, void * buffer, uint16_t n); #ifdef TUP_MEM_CONST_ADDR -uint16_t tu_fifo_read_n_const_addr_full_words (tu_fifo_t* f, void * buffer, uint16_t n); +uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t *f, const void *data, uint16_t n); +uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t *f, void *buffer, uint16_t n); #endif -bool tu_fifo_peek (tu_fifo_t* f, void * p_buffer); -uint16_t tu_fifo_peek_n (tu_fifo_t* f, void * p_buffer, uint16_t n); +bool tu_fifo_peek(tu_fifo_t *f, void *p_buffer); +uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n); -uint16_t tu_fifo_count (tu_fifo_t* f); -uint16_t tu_fifo_remaining (tu_fifo_t* f); -bool tu_fifo_empty (tu_fifo_t* f); -bool tu_fifo_full (tu_fifo_t* f); -bool tu_fifo_overflowed (tu_fifo_t* f); -void tu_fifo_correct_read_pointer (tu_fifo_t* f); +uint16_t tu_fifo_count(const tu_fifo_t *f); +uint16_t tu_fifo_remaining(const tu_fifo_t *f); +bool tu_fifo_full(const tu_fifo_t *f); +bool tu_fifo_overflowed(const tu_fifo_t *f); -TU_ATTR_ALWAYS_INLINE static inline -uint16_t tu_fifo_depth(tu_fifo_t* f) { +TU_ATTR_ALWAYS_INLINE static inline bool tu_fifo_empty(const tu_fifo_t *f) { + return f->wr_idx == f->rd_idx; +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_depth(const tu_fifo_t *f) { return f->depth; } +void tu_fifo_correct_read_pointer(tu_fifo_t *f); + // Pointer modifications intended to be used in combinations with DMAs. // USE WITH CARE - NO SAFETY CHECKS CONDUCTED HERE! NOT MUTEX PROTECTED! void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n); diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index dcd5c45d6..367209e57 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -105,6 +105,10 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_open(tu_edpt_stream_t* s s->is_mps512 = tu_edpt_packet_size(desc_ep) == 512; } +TU_ATTR_ALWAYS_INLINE static inline bool tu_edpt_stream_is_opened(const tu_edpt_stream_t *s) { + return s->ep_addr != 0; +} + TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_close(tu_edpt_stream_t* s) { s->ep_addr = 0; } @@ -121,7 +125,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool tu_edpt_stream_clear(tu_edpt_stream_t* // Write to stream uint32_t tu_edpt_stream_write(uint8_t hwid, tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize); -// Start an usb transfer if endpoint is not busy +// Start an usb transfer if endpoint is not busy. Return number of queued bytes uint32_t tu_edpt_stream_write_xfer(uint8_t hwid, tu_edpt_stream_t* s); // Start an zero-length packet if needed @@ -151,20 +155,18 @@ void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_byt // Complete read transfer with provided buffer TU_ATTR_ALWAYS_INLINE static inline -void tu_edpt_stream_read_xfer_complete_with_buf(tu_edpt_stream_t* s, const void * buf, uint32_t xferred_bytes) { +void tu_edpt_stream_read_xfer_complete_with_buf(tu_edpt_stream_t *s, const void *buf, uint32_t xferred_bytes) { if (0u != tu_fifo_depth(&s->ff)) { tu_fifo_write_n(&s->ff, buf, (uint16_t) xferred_bytes); } } // Get the number of bytes available for reading -TU_ATTR_ALWAYS_INLINE static inline -uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t* s) { +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_edpt_stream_read_available(const tu_edpt_stream_t *s) { return (uint32_t) tu_fifo_count(&s->ff); } -TU_ATTR_ALWAYS_INLINE static inline -bool tu_edpt_stream_peek(tu_edpt_stream_t* s, uint8_t* ch) { +TU_ATTR_ALWAYS_INLINE static inline bool tu_edpt_stream_peek(tu_edpt_stream_t *s, uint8_t *ch) { return tu_fifo_peek(&s->ff, ch); } diff --git a/src/tusb.c b/src/tusb.c index 7411f19df..b308e2915 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -424,7 +424,7 @@ uint32_t tu_edpt_stream_write_xfer(uint8_t hwid, tu_edpt_stream_t* s) { TU_VERIFY(stream_claim(hwid, s), 0); // Pull data from FIFO -> EP buf - uint16_t const count = tu_fifo_read_n(&s->ff, s->ep_buf, s->ep_bufsize); + const uint16_t count = tu_fifo_read_n(&s->ff, s->ep_buf, s->ep_bufsize); if (count > 0) { TU_ASSERT(stream_xfer(hwid, s, count), 0); @@ -437,7 +437,7 @@ uint32_t tu_edpt_stream_write_xfer(uint8_t hwid, tu_edpt_stream_t* s) { } } -uint32_t tu_edpt_stream_write(uint8_t hwid, tu_edpt_stream_t* s, void const* buffer, uint32_t bufsize) { +uint32_t tu_edpt_stream_write(uint8_t hwid, tu_edpt_stream_t *s, const void *buffer, uint32_t bufsize) { TU_VERIFY(bufsize > 0); // TODO support ZLP if (0 == tu_fifo_depth(&s->ff)) { -- cgit v1.3.1 From f11adb02ebc0c594a7114b08585b8af18c3ee6d6 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 12 Nov 2025 21:22:25 +0700 Subject: migrate cdc device to use edpt stream API tu_edpt_stream_open() does not clear fifo, allow for persistent stream when disconnect/reconnect --- .clang-format | 7 +- .../net_lwip_webserver/src/usb_descriptors.c | 2 +- src/class/cdc/cdc_device.c | 393 +++++++++------------ src/class/midi/midi_device.c | 2 + src/class/vendor/vendor_device.c | 16 +- src/common/tusb_private.h | 7 +- src/tusb.c | 8 +- 7 files changed, 194 insertions(+), 241 deletions(-) (limited to 'src/class') diff --git a/.clang-format b/.clang-format index c278fec37..40d40f7e9 100644 --- a/.clang-format +++ b/.clang-format @@ -1,7 +1,7 @@ --- Language: Cpp BasedOnStyle: LLVM -AlignAfterOpenBracket: AlwaysBreak +AlignAfterOpenBracket: Align AlignConsecutiveAssignments: Enabled: true AcrossEmptyLines: false @@ -38,6 +38,7 @@ AllowShortEnumsOnASingleLine: false AllowShortFunctionsOnASingleLine: None AllowShortIfStatementsOnASingleLine: Never AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true BreakBeforeBraces: Custom BraceWrapping: AfterCaseLabel: false @@ -57,8 +58,10 @@ BraceWrapping: SplitEmptyRecord: true SplitEmptyNamespace: true BracedInitializerIndentWidth: 2 +BreakBeforeBinaryOperators: None BreakConstructorInitializers: AfterColon BreakConstructorInitializersBeforeComma: false +ContinuationIndentWidth: 2 ColumnLimit: 120 ConstructorInitializerAllOnOneLineOrOnePerLine: false Cpp11BracedListStyle: true @@ -78,6 +81,8 @@ MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 2 NamespaceIndentation: All +PenaltyBreakBeforeFirstCallParameter: 1000000 +PenaltyBreakOpenParenthesis: 1000000 QualifierAlignment: Custom QualifierOrder: ['static', 'const', 'volatile', 'restrict', 'type'] ReflowComments: false diff --git a/examples/device/net_lwip_webserver/src/usb_descriptors.c b/examples/device/net_lwip_webserver/src/usb_descriptors.c index b49962d65..c976cb62b 100644 --- a/examples/device/net_lwip_webserver/src/usb_descriptors.c +++ b/examples/device/net_lwip_webserver/src/usb_descriptors.c @@ -270,7 +270,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_contro switch (request->bmRequestType_bit.type) { case TUSB_REQ_TYPE_VENDOR: - switch (request->bRequest) { //-V2520 //-V2659 + switch (request->bRequest) { case 1: if (request->wIndex == 7) { // Get Microsoft OS 2.0 compatible descriptor diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index b3253b141..92139b14e 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -48,28 +48,23 @@ typedef struct { uint8_t rhport; uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; - uint8_t ep_notify; uint8_t line_state; // Bit 0: DTR, Bit 1: RTS /*------------- From this point, data is not cleared by bus reset -------------*/ - char wanted_char; TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; + char wanted_char; - // FIFO - tu_fifo_t rx_ff; - tu_fifo_t tx_ff; - - uint8_t rx_ff_buf[CFG_TUD_CDC_RX_BUFSIZE]; - uint8_t tx_ff_buf[CFG_TUD_CDC_TX_BUFSIZE]; + struct { + tu_edpt_stream_t tx; + tu_edpt_stream_t rx; - OSAL_MUTEX_DEF(rx_ff_mutex); - OSAL_MUTEX_DEF(tx_ff_mutex); + uint8_t tx_ff_buf[CFG_TUD_CDC_TX_BUFSIZE]; + uint8_t rx_ff_buf[CFG_TUD_CDC_RX_BUFSIZE]; + } stream; } cdcd_interface_t; -#define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, wanted_char) +#define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, line_coding) typedef struct { TUD_EPBUF_DEF(epout, CFG_TUD_CDC_EP_BUFSIZE); @@ -80,111 +75,102 @@ typedef struct { #endif } cdcd_epbuf_t; -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; -CFG_TUD_MEM_SECTION static cdcd_epbuf_t _cdcd_epbuf[CFG_TUD_CDC]; - -static tud_cdc_configure_t _cdcd_cfg = TUD_CDC_CONFIGURE_DEFAULT(); - -static bool _prep_out_transaction(uint8_t itf) { - const uint8_t rhport = 0; - cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; - cdcd_epbuf_t* p_epbuf = &_cdcd_epbuf[itf]; - - // 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. - // TODO Actually we can still carry out the transfer, keeping count of received bytes - // and slowly move it to the FIFO when read(). - // This pre-check reduces endpoint claiming - TU_VERIFY(available >= CFG_TUD_CDC_EP_BUFSIZE); - - // claim endpoint - TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_out)); - - // fifo can be changed before endpoint is claimed - available = tu_fifo_remaining(&p_cdc->rx_ff); - - if (available >= CFG_TUD_CDC_EP_BUFSIZE) { - return usbd_edpt_xfer(rhport, p_cdc->ep_out, p_epbuf->epout, CFG_TUD_CDC_EP_BUFSIZE); - } else { - // Release endpoint since we don't make any transfer - usbd_edpt_release(p_cdc->rhport, p_cdc->ep_out); - return false; - } -} - //--------------------------------------------------------------------+ // Weak stubs: invoked if no strong implementation is available //--------------------------------------------------------------------+ TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf) { - (void) itf; + (void)itf; } TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) { - (void) itf; - (void) wanted_char; + (void)itf; + (void)wanted_char; } TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf) { - (void) itf; + (void)itf; } TU_ATTR_WEAK void tud_cdc_notify_complete_cb(uint8_t itf) { - (void) itf; + (void)itf; } TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) { - (void) itf; - (void) dtr; - (void) rts; + (void)itf; + (void)dtr; + (void)rts; } -TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding) { - (void) itf; - (void) p_line_coding; +TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, const cdc_line_coding_t *p_line_coding) { + (void)itf; + (void)p_line_coding; } TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms) { - (void) itf; - (void) duration_ms; + (void)itf; + (void)duration_ms; +} + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; +CFG_TUD_MEM_SECTION static cdcd_epbuf_t _cdcd_epbuf[CFG_TUD_CDC]; +static tud_cdc_configure_t _cdcd_cfg = TUD_CDC_CONFIGURE_DEFAULT(); + +TU_ATTR_ALWAYS_INLINE static inline uint8_t find_cdc_itf(uint8_t ep_addr) { + for (uint8_t idx = 0; idx < CFG_TUD_CDC; idx++) { + const cdcd_interface_t *p_cdc = &_cdcd_itf[idx]; + if (ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr || + (ep_addr == p_cdc->ep_notify && ep_addr != 0)) { + return idx; + } + } + return TUSB_INDEX_INVALID_8; } //--------------------------------------------------------------------+ // APPLICATION API //--------------------------------------------------------------------+ bool tud_cdc_configure(const tud_cdc_configure_t* driver_cfg) { - TU_VERIFY(driver_cfg); + TU_VERIFY(driver_cfg != NULL); _cdcd_cfg = *driver_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; + TU_VERIFY(itf < CFG_TUD_CDC); + TU_VERIFY(tud_ready()); + cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; + + const bool in_opened = tu_edpt_stream_is_opened(&p_cdc->stream.tx); + const bool out_opened = tu_edpt_stream_is_opened(&p_cdc->stream.rx); + return in_opened && out_opened; } bool tud_cdc_n_connected(uint8_t itf) { + TU_VERIFY(itf < CFG_TUD_CDC); + TU_VERIFY(tud_ready()); + cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; // DTR (bit 0) active is considered as connected - return tud_ready() && tu_bit_test(_cdcd_itf[itf].line_state, 0); + return tu_bit_test(p_cdc->line_state, 0); } uint8_t tud_cdc_n_get_line_state(uint8_t itf) { + TU_VERIFY(itf < CFG_TUD_CDC, 0); 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) { + TU_VERIFY(itf < CFG_TUD_CDC, ); (*coding) = _cdcd_itf[itf].line_coding; } #if CFG_TUD_CDC_NOTIFY bool tud_cdc_n_notify_uart_state (uint8_t itf, const cdc_notify_uart_state_t *state) { - cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; - cdcd_epbuf_t* p_epbuf = &_cdcd_epbuf[itf]; + TU_VERIFY(itf < CFG_TUD_CDC); + cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; + cdcd_epbuf_t *p_epbuf = &_cdcd_epbuf[itf]; TU_VERIFY(tud_ready() && p_cdc->ep_notify != 0); TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_notify)); @@ -200,8 +186,9 @@ bool tud_cdc_n_notify_uart_state (uint8_t itf, const cdc_notify_uart_state_t *st } bool tud_cdc_n_notify_conn_speed_change(uint8_t itf, const cdc_notify_conn_speed_change_t* conn_speed_change) { - cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; - cdcd_epbuf_t* p_epbuf = &_cdcd_epbuf[itf]; + TU_VERIFY(itf < CFG_TUD_CDC); + cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; + cdcd_epbuf_t *p_epbuf = &_cdcd_epbuf[itf]; TU_VERIFY(tud_ready() && p_cdc->ep_notify != 0); TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_notify)); @@ -218,6 +205,7 @@ bool tud_cdc_n_notify_conn_speed_change(uint8_t itf, const cdc_notify_conn_speed #endif void tud_cdc_n_set_wanted_char(uint8_t itf, char wanted) { + TU_VERIFY(itf < CFG_TUD_CDC, ); _cdcd_itf[itf].wanted_char = wanted; } @@ -225,77 +213,55 @@ void tud_cdc_n_set_wanted_char(uint8_t itf, char wanted) { // READ API //--------------------------------------------------------------------+ uint32_t tud_cdc_n_available(uint8_t itf) { - return tu_fifo_count(&_cdcd_itf[itf].rx_ff); + TU_VERIFY(itf < CFG_TUD_CDC, 0); + cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; + return tu_edpt_stream_read_available(&p_cdc->stream.rx); } 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(itf); - return num_read; + TU_VERIFY(itf < CFG_TUD_CDC, 0); + cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; + return tu_edpt_stream_read(p_cdc->rhport, &p_cdc->stream.rx, buffer, bufsize); } -bool tud_cdc_n_peek(uint8_t itf, uint8_t* chr) { - return tu_fifo_peek(&_cdcd_itf[itf].rx_ff, chr); +bool tud_cdc_n_peek(uint8_t itf, uint8_t *chr) { + TU_VERIFY(itf < CFG_TUD_CDC); + cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; + return tu_edpt_stream_peek(&p_cdc->stream.rx, chr); } 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(itf); + TU_VERIFY(itf < CFG_TUD_CDC, ); + cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; + tu_edpt_stream_clear(&p_cdc->stream.rx); + tu_edpt_stream_read_xfer(p_cdc->rhport, &p_cdc->stream.rx); } //--------------------------------------------------------------------+ // WRITE API //--------------------------------------------------------------------+ uint32_t tud_cdc_n_write(uint8_t itf, const void* buffer, uint32_t bufsize) { - cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; - uint16_t wr_count = 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 - ) { - tud_cdc_n_write_flush(itf); - } - - return wr_count; + TU_VERIFY(itf < CFG_TUD_CDC, 0); + cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; + return tu_edpt_stream_write(p_cdc->rhport, &p_cdc->stream.tx, buffer, bufsize); } uint32_t tud_cdc_n_write_flush(uint8_t itf) { - cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; - cdcd_epbuf_t* p_epbuf = &_cdcd_epbuf[itf]; - TU_VERIFY(tud_ready(), 0); // Skip if usb is not ready yet - - // No data to send - if (0 == tu_fifo_count(&p_cdc->tx_ff)) { - return 0; - } - - TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_in), 0); // Claim the endpoint - - // Pull data from FIFO - const uint16_t count = tu_fifo_read_n(&p_cdc->tx_ff, p_epbuf->epin, CFG_TUD_CDC_EP_BUFSIZE); - - if (count > 0) { - TU_ASSERT(usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_in, p_epbuf->epin, count), 0); - return count; - } else { - // Release endpoint since we don't make any transfer - // Note: data is dropped if terminal is not connected - usbd_edpt_release(p_cdc->rhport, p_cdc->ep_in); - return 0; - } + TU_VERIFY(itf < CFG_TUD_CDC, 0); + cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; + return tu_edpt_stream_write_xfer(p_cdc->rhport, &p_cdc->stream.tx); } uint32_t tud_cdc_n_write_available(uint8_t itf) { - return tu_fifo_remaining(&_cdcd_itf[itf].tx_ff); + TU_VERIFY(itf < CFG_TUD_CDC, 0); + cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; + return tu_edpt_stream_write_available(p_cdc->rhport, &p_cdc->stream.tx); } bool tud_cdc_n_write_clear(uint8_t itf) { - return tu_fifo_clear(&_cdcd_itf[itf].tx_ff); + TU_VERIFY(itf < CFG_TUD_CDC); + cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; + return tu_edpt_stream_clear(&p_cdc->stream.tx); } //--------------------------------------------------------------------+ @@ -304,7 +270,8 @@ bool tud_cdc_n_write_clear(uint8_t itf) { void cdcd_init(void) { tu_memclr(_cdcd_itf, sizeof(_cdcd_itf)); for (uint8_t i = 0; i < CFG_TUD_CDC; i++) { - cdcd_interface_t* p_cdc = &_cdcd_itf[i]; + cdcd_interface_t *p_cdc = &_cdcd_itf[i]; + cdcd_epbuf_t *p_epbuf = &_cdcd_epbuf[i]; p_cdc->wanted_char = (char) -1; @@ -314,44 +281,23 @@ void cdcd_init(void) { p_cdc->line_coding.parity = 0; p_cdc->line_coding.data_bits = 8; - // Config RX fifo - tu_fifo_config(&p_cdc->rx_ff, p_cdc->rx_ff_buf, TU_ARRAY_SIZE(p_cdc->rx_ff_buf), 1, false); + tu_edpt_stream_init(&p_cdc->stream.rx, false, false, false, p_cdc->stream.rx_ff_buf, CFG_TUD_CDC_RX_BUFSIZE, + p_epbuf->epout, CFG_TUD_CDC_EP_BUFSIZE); // TX fifo can be configured to change to overwritable if not connected (DTR bit not set). Without DTR we do not // know if data is actually polled by terminal. This way the most current data is prioritized. // Default: is overwritable - tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, _cdcd_cfg.tx_overwritabe_if_not_connected); - - #if OSAL_MUTEX_REQUIRED - osal_mutex_t mutex_rd = osal_mutex_create(&p_cdc->rx_ff_mutex); - osal_mutex_t mutex_wr = osal_mutex_create(&p_cdc->tx_ff_mutex); - TU_ASSERT(mutex_rd != NULL && mutex_wr != NULL, ); - - tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, mutex_rd); - tu_fifo_config_mutex(&p_cdc->tx_ff, mutex_wr, NULL); - #endif + tu_edpt_stream_init(&p_cdc->stream.tx, false, true, _cdcd_cfg.tx_overwritabe_if_not_connected, + p_cdc->stream.tx_ff_buf, CFG_TUD_CDC_TX_BUFSIZE, p_epbuf->epin, CFG_TUD_CDC_EP_BUFSIZE); } } bool cdcd_deinit(void) { - #if OSAL_MUTEX_REQUIRED for(uint8_t i=0; irx_ff.mutex_rd; - const osal_mutex_t mutex_wr = p_cdc->tx_ff.mutex_wr; - - if (mutex_rd != NULL) { - osal_mutex_delete(mutex_rd); - tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, NULL); - } - - if (mutex_wr != NULL) { - osal_mutex_delete(mutex_wr); - tu_fifo_config_mutex(&p_cdc->tx_ff, NULL, NULL); - } + tu_edpt_stream_deinit(&p_cdc->stream.rx); + tu_edpt_stream_deinit(&p_cdc->stream.tx); } - #endif - return true; } @@ -360,74 +306,85 @@ void cdcd_reset(uint8_t rhport) { 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); - if (!_cdcd_cfg.rx_persistent) { - tu_fifo_clear(&p_cdc->rx_ff); - } - if (!_cdcd_cfg.tx_persistent) { - tu_fifo_clear(&p_cdc->tx_ff); - } - tu_fifo_set_overwritable(&p_cdc->tx_ff, _cdcd_cfg.tx_overwritabe_if_not_connected); + + tu_fifo_set_overwritable(&p_cdc->stream.tx.ff, _cdcd_cfg.tx_overwritabe_if_not_connected); // // back to default + tu_edpt_stream_close(&p_cdc->stream.rx); + tu_edpt_stream_close(&p_cdc->stream.tx); } } uint16_t cdcd_open(uint8_t rhport, const tusb_desc_interface_t* 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); + 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; - uint8_t cdc_id; - for (cdc_id = 0; cdc_id < CFG_TUD_CDC; cdc_id++) { - p_cdc = &_cdcd_itf[cdc_id]; - if (p_cdc->ep_in == 0) { - break; - } - } + const uint8_t cdc_id = find_cdc_itf(0); // Find available interface TU_ASSERT(cdc_id < CFG_TUD_CDC, 0); + cdcd_interface_t *p_cdc = &_cdcd_itf[cdc_id]; //------------- Control Interface -------------// p_cdc->rhport = rhport; p_cdc->itf_num = itf_desc->bInterfaceNumber; - uint16_t drv_len = sizeof(tusb_desc_interface_t); - const uint8_t* p_desc = tu_desc_next(itf_desc); + const uint8_t *p_desc = (const uint8_t *)itf_desc; + const uint8_t *desc_end = p_desc + max_len; - // Communication Functional Descriptors - while (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len) { - drv_len += tu_desc_len(p_desc); + // Skip all class-specific descriptor + p_desc = tu_desc_next(itf_desc); + while (tu_desc_in_bounds(p_desc, desc_end) && TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc)) { p_desc = tu_desc_next(p_desc); } + // notification endpoint (optional) if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) { - // notification endpoint const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc; TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); p_cdc->ep_notify = desc_ep->bEndpointAddress; - drv_len += tu_desc_len(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 == ((const tusb_desc_interface_t*) p_desc)->bInterfaceClass)) { - // next to endpoint descriptor - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); + //------------- Data Interface (optional) -------------// + if (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) { + const tusb_desc_interface_t *data_itf_desc = (const tusb_desc_interface_t *)p_desc; + if (TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass) { + for (uint8_t e = 0; e < data_itf_desc->bNumEndpoints; e++) { + if (!tu_desc_in_bounds(p_desc, desc_end)) { + break; + } + 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); + const tusb_desc_endpoint_t *desc_ep = (const tusb_desc_endpoint_t *)p_desc; + TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer, 0); - drv_len += 2 * sizeof(tusb_desc_endpoint_t); - } + TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { + tu_edpt_stream_t *stream_tx = &p_cdc->stream.tx; + tu_edpt_stream_open(stream_tx, desc_ep); + + if (_cdcd_cfg.tx_persistent) { + tu_edpt_stream_write_xfer(rhport, stream_tx); // flush pending data + } else { + tu_edpt_stream_clear(stream_tx); + } + } else { + tu_edpt_stream_t *stream_rx = &p_cdc->stream.rx; - // Prepare for incoming data - _prep_out_transaction(cdc_id); + tu_edpt_stream_open(stream_rx, desc_ep); + if (!_cdcd_cfg.rx_persistent) { + tu_edpt_stream_clear(stream_rx); + } + TU_ASSERT(tu_edpt_stream_read_xfer(rhport, stream_rx) > 0, 0); // prepare for incoming data + } + } - return drv_len; + p_desc = tu_desc_next(p_desc); + } + } + + return p_desc - (const uint8_t *)itf_desc; } // Invoked when a control transfer occurred on an interface of this class @@ -449,7 +406,7 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_requ } TU_VERIFY(itf < CFG_TUD_CDC); - switch (request->bRequest) { //-V2520 //-V2659 + switch (request->bRequest) { case CDC_REQUEST_SET_LINE_CODING: if (stage == CONTROL_STAGE_SETUP) { TU_LOG_DRV(" Set Line Coding\r\n"); @@ -484,15 +441,13 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_requ // If enabled: fifo overwriting is disabled if DTR bit is set and vice versa if (_cdcd_cfg.tx_overwritabe_if_not_connected) { - tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr); + tu_fifo_set_overwritable(&p_cdc->stream.tx.ff, !dtr); } else { - tu_fifo_set_overwritable(&p_cdc->tx_ff, false); + tu_fifo_set_overwritable(&p_cdc->stream.tx.ff, false); } TU_LOG_DRV(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); - - // Invoke callback - tud_cdc_line_state_cb(itf, dtr, rts); + tud_cdc_line_state_cb(itf, dtr, rts); // invoke callback } else { // nothing to do } @@ -507,7 +462,6 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_requ } else { // nothing to do } - break; default: @@ -518,58 +472,45 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_requ } bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { - (void) result; + (void)result; - uint8_t itf; - cdcd_interface_t* p_cdc; - - // Identify which interface to use - 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) || (ep_addr == p_cdc->ep_notify)) { - break; - } - } + uint8_t itf = find_cdc_itf(ep_addr); TU_ASSERT(itf < CFG_TUD_CDC); - cdcd_epbuf_t* p_epbuf = &_cdcd_epbuf[itf]; + cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; + tu_edpt_stream_t *stream_rx = &p_cdc->stream.rx; + tu_edpt_stream_t *stream_tx = &p_cdc->stream.tx; - // Received new data - if (ep_addr == p_cdc->ep_out) { - tu_fifo_write_n(&p_cdc->rx_ff, p_epbuf->epout, (uint16_t) xferred_bytes); + // Received new data, move to fifo + if (ep_addr == stream_rx->ep_addr) { + tu_edpt_stream_read_xfer_complete(stream_rx, xferred_bytes); - // Check for wanted char and invoke callback if needed - if (((signed char) p_cdc->wanted_char) != -1) { + // Check for wanted char and invoke wanted callback (multiple times if multiple wanted received) + if (((signed char)p_cdc->wanted_char) != -1) { for (uint32_t i = 0; i < xferred_bytes; i++) { - if ((p_cdc->wanted_char == (char) p_epbuf->epout[i]) && !tu_fifo_empty(&p_cdc->rx_ff)) { + if ((p_cdc->wanted_char == (char)stream_rx->ep_buf[i]) && !tu_edpt_stream_empty(stream_rx)) { tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char); } } } - // invoke receive callback (if there is still data) - if (!tu_fifo_empty(&p_cdc->rx_ff)) { + // invoke receive callback if there is still data + if (!tu_edpt_stream_empty(stream_rx)) { tud_cdc_rx_cb(itf); } - // prepare for OUT transaction - _prep_out_transaction(itf); + tu_edpt_stream_read_xfer(rhport, stream_rx); // prepare for more data } // 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 == stream_tx->ep_addr) { // invoke transmit callback to possibly refill tx fifo tud_cdc_tx_complete_cb(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 (0 == tu_fifo_count(&p_cdc->tx_ff) && xferred_bytes > 0 && (0 == (xferred_bytes & (BULK_PACKET_SIZE - 1)))) { - if (usbd_edpt_claim(rhport, p_cdc->ep_in)) { - TU_ASSERT(usbd_edpt_xfer(rhport, p_cdc->ep_in, NULL, 0)); - } - } + if (0 == tu_edpt_stream_write_xfer(rhport, stream_tx)) { + // If there is no data left, a ZLP should be sent if needed + tu_edpt_stream_write_zlp_if_needed(rhport, stream_tx, xferred_bytes); } } diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index f065e486a..79e7dfa71 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -405,8 +405,10 @@ uint16_t midid_open(uint8_t rhport, const tusb_desc_interface_t *desc_itf, uint1 if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { tu_edpt_stream_open(&p_midi->ep_stream.tx, desc_ep); + tu_edpt_stream_clear(&p_midi->ep_stream.tx); } else { tu_edpt_stream_open(&p_midi->ep_stream.rx, desc_ep); + tu_edpt_stream_clear(&p_midi->ep_stream.rx); TU_ASSERT(tu_edpt_stream_read_xfer(rhport, &p_midi->ep_stream.rx) > 0, 0); // prepare to receive data } diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index c916ebe47..7da4d2239 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -234,16 +234,18 @@ uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uin const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc; TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); - // open endpoint stream, skip if already opened + // open endpoint stream, skip if already opened (multiple IN/OUT endpoints) if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { - if (p_vendor->tx.stream.ep_addr == 0) { - tu_edpt_stream_open(&p_vendor->tx.stream, desc_ep); - tud_vendor_n_write_flush(itf); + tu_edpt_stream_t *stream_tx = &p_vendor->tx.stream; + if (stream_tx->ep_addr == 0) { + tu_edpt_stream_open(stream_tx, desc_ep); + tu_edpt_stream_write_xfer(rhport, stream_tx); // flush pending data } } else { - if (p_vendor->rx.stream.ep_addr == 0) { - tu_edpt_stream_open(&p_vendor->rx.stream, desc_ep); - TU_ASSERT(tu_edpt_stream_read_xfer(rhport, &p_vendor->rx.stream) > 0, 0); // prepare for incoming data + tu_edpt_stream_t *stream_rx = &p_vendor->rx.stream; + if (stream_rx->ep_addr == 0) { + tu_edpt_stream_open(stream_rx, desc_ep); + TU_ASSERT(tu_edpt_stream_read_xfer(rhport, stream_rx) > 0, 0); // prepare for incoming data } } } diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index 367209e57..f82f87b6f 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -100,7 +100,6 @@ bool tu_edpt_stream_deinit(tu_edpt_stream_t* s); // Open an stream for an endpoint TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_open(tu_edpt_stream_t* s, tusb_desc_endpoint_t const *desc_ep) { - tu_fifo_clear(&s->ff); s->ep_addr = desc_ep->bEndpointAddress; s->is_mps512 = tu_edpt_packet_size(desc_ep) == 512; } @@ -113,11 +112,15 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_close(tu_edpt_stream_t* s->ep_addr = 0; } -// Clear fifo TU_ATTR_ALWAYS_INLINE static inline bool tu_edpt_stream_clear(tu_edpt_stream_t* s) { return tu_fifo_clear(&s->ff); } +TU_ATTR_ALWAYS_INLINE static inline bool tu_edpt_stream_empty(tu_edpt_stream_t *s) { + return tu_fifo_empty(&s->ff); +} + + //--------------------------------------------------------------------+ // Stream Write //--------------------------------------------------------------------+ diff --git a/src/tusb.c b/src/tusb.c index b308e2915..df33f2680 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -354,8 +354,8 @@ bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool ove return true; } -bool tu_edpt_stream_deinit(tu_edpt_stream_t* s) { - (void) s; +bool tu_edpt_stream_deinit(tu_edpt_stream_t *s) { + (void)s; #if OSAL_MUTEX_REQUIRED if (s->ff.mutex_wr) { osal_mutex_delete(s->ff.mutex_wr); @@ -363,7 +363,7 @@ bool tu_edpt_stream_deinit(tu_edpt_stream_t* s) { if (s->ff.mutex_rd) { osal_mutex_delete(s->ff.mutex_rd); } -#endif + #endif return true; } @@ -412,7 +412,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool stream_release(uint8_t hwid, tu_edpt_st bool tu_edpt_stream_write_zlp_if_needed(uint8_t hwid, tu_edpt_stream_t* s, uint32_t last_xferred_bytes) { // ZLP condition: no pending data, last transferred bytes is multiple of packet size const uint16_t mps = s->is_mps512 ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; - TU_VERIFY(!tu_fifo_count(&s->ff) && last_xferred_bytes > 0 && (0 == (last_xferred_bytes & (mps - 1)))); + TU_VERIFY(tu_fifo_empty(&s->ff) && last_xferred_bytes > 0 && (0 == (last_xferred_bytes & (mps - 1)))); TU_VERIFY(stream_claim(hwid, s)); TU_ASSERT(stream_xfer(hwid, s, 0)); return true; -- cgit v1.3.1 From 397a3af8afc4bc5460572da4a40629684dfa788c Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 13 Nov 2025 12:02:02 +0700 Subject: clear endpoint stream when open for cdc_host and midi_host --- src/class/cdc/cdc_device.c | 15 ++++++------- src/class/cdc/cdc_host.c | 50 ++++++++++++++++++-------------------------- src/class/midi/midi_device.c | 14 +++++++------ src/class/midi/midi_host.c | 48 ++++++++++++++++++++++-------------------- src/common/tusb_common.h | 2 +- src/common/tusb_private.h | 1 - src/tusb.c | 2 +- 7 files changed, 61 insertions(+), 71 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 92139b14e..80fa81d99 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -141,7 +141,7 @@ bool tud_cdc_configure(const tud_cdc_configure_t* driver_cfg) { bool tud_cdc_n_ready(uint8_t itf) { TU_VERIFY(itf < CFG_TUD_CDC); TU_VERIFY(tud_ready()); - cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; + const cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; const bool in_opened = tu_edpt_stream_is_opened(&p_cdc->stream.tx); const bool out_opened = tu_edpt_stream_is_opened(&p_cdc->stream.rx); @@ -151,9 +151,8 @@ bool tud_cdc_n_ready(uint8_t itf) { bool tud_cdc_n_connected(uint8_t itf) { TU_VERIFY(itf < CFG_TUD_CDC); TU_VERIFY(tud_ready()); - cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; // DTR (bit 0) active is considered as connected - return tu_bit_test(p_cdc->line_state, 0); + return tu_bit_test(_cdcd_itf[itf].line_state, 0); } uint8_t tud_cdc_n_get_line_state(uint8_t itf) { @@ -214,8 +213,7 @@ void tud_cdc_n_set_wanted_char(uint8_t itf, char wanted) { //--------------------------------------------------------------------+ uint32_t tud_cdc_n_available(uint8_t itf) { TU_VERIFY(itf < CFG_TUD_CDC, 0); - cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; - return tu_edpt_stream_read_available(&p_cdc->stream.rx); + return tu_edpt_stream_read_available(&_cdcd_itf[itf].stream.rx); } uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize) { @@ -226,8 +224,7 @@ uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize) { bool tud_cdc_n_peek(uint8_t itf, uint8_t *chr) { TU_VERIFY(itf < CFG_TUD_CDC); - cdcd_interface_t *p_cdc = &_cdcd_itf[itf]; - return tu_edpt_stream_peek(&p_cdc->stream.rx, chr); + return tu_edpt_stream_peek(&_cdcd_itf[itf].stream.rx, chr); } void tud_cdc_n_read_flush(uint8_t itf) { @@ -362,8 +359,8 @@ uint16_t cdcd_open(uint8_t rhport, const tusb_desc_interface_t* itf_desc, uint16 TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { tu_edpt_stream_t *stream_tx = &p_cdc->stream.tx; - tu_edpt_stream_open(stream_tx, desc_ep); + tu_edpt_stream_open(stream_tx, desc_ep); if (_cdcd_cfg.tx_persistent) { tu_edpt_stream_write_xfer(rhport, stream_tx); // flush pending data } else { @@ -384,7 +381,7 @@ uint16_t cdcd_open(uint8_t rhport, const tusb_desc_interface_t* itf_desc, uint16 } } - return p_desc - (const uint8_t *)itf_desc; + return (uint16_t)(p_desc - (const uint8_t *)itf_desc); } // Invoked when a control transfer occurred on an interface of this class diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 7fdf0a7b9..35717ddf6 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -298,6 +298,7 @@ TU_VERIFY_STATIC(TU_ARRAY_SIZE(serial_drivers) == SERIAL_DRIVER_COUNT, "Serial d //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ +static bool open_ep_stream_pair(cdch_interface_t *p_cdc, const tusb_desc_endpoint_t *desc_ep); TU_ATTR_ALWAYS_INLINE static inline cdch_interface_t * get_itf(uint8_t idx) { TU_ASSERT(idx < CFG_TUH_CDC, NULL); @@ -364,7 +365,7 @@ static cdch_interface_t* get_itf_by_xfer(const tuh_xfer_t * xfer) { #endif default: - break; + break; // unknown driver } } } @@ -389,8 +390,6 @@ static cdch_interface_t * make_new_itf(uint8_t daddr, tusb_desc_interface_t cons return NULL; } -static bool open_ep_stream_pair(cdch_interface_t * p_cdc , tusb_desc_endpoint_t const *desc_ep); - //--------------------------------------------------------------------+ // Weak stubs: invoked if no strong implementation is available //--------------------------------------------------------------------+ @@ -519,7 +518,7 @@ bool tuh_cdc_read_clear (uint8_t idx) { TU_VERIFY(p_cdc); bool ret = tu_edpt_stream_clear(&p_cdc->stream.rx); - tu_edpt_stream_read_xfer(p_cdc->daddr, &p_cdc->stream.rx); + (void)tu_edpt_stream_read_xfer(p_cdc->daddr, &p_cdc->stream.rx); return ret; } @@ -648,13 +647,10 @@ bool cdch_init(void) { for (size_t i = 0; i < CFG_TUH_CDC; i++) { cdch_interface_t *p_cdc = &cdch_data[i]; cdch_epbuf_t *epbuf = &cdch_epbuf[i]; - tu_edpt_stream_init(&p_cdc->stream.tx, true, true, false, - p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, - epbuf->tx, CFG_TUH_CDC_TX_EPSIZE); - - tu_edpt_stream_init(&p_cdc->stream.rx, true, false, false, - p_cdc->stream.rx_ff_buf, CFG_TUH_CDC_RX_BUFSIZE, - epbuf->rx, CFG_TUH_CDC_RX_EPSIZE); + TU_ASSERT(tu_edpt_stream_init(&p_cdc->stream.tx, true, true, false, p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, + epbuf->tx, CFG_TUH_CDC_TX_EPSIZE)); + TU_ASSERT(tu_edpt_stream_init(&p_cdc->stream.rx, true, false, false, p_cdc->stream.rx_ff_buf, + CFG_TUH_CDC_RX_BUFSIZE, epbuf->rx, CFG_TUH_CDC_RX_EPSIZE)); } return true; @@ -663,8 +659,8 @@ bool cdch_init(void) { bool cdch_deinit(void) { for (size_t i = 0; i < CFG_TUH_CDC; i++) { cdch_interface_t *p_cdc = &cdch_data[i]; - tu_edpt_stream_deinit(&p_cdc->stream.tx); - tu_edpt_stream_deinit(&p_cdc->stream.rx); + (void)tu_edpt_stream_deinit(&p_cdc->stream.tx); + (void)tu_edpt_stream_deinit(&p_cdc->stream.rx); } return true; } @@ -674,11 +670,9 @@ void cdch_close(uint8_t daddr) { cdch_interface_t *p_cdc = &cdch_data[idx]; if (p_cdc->daddr == daddr) { TU_LOG_CDC(p_cdc, "close"); + tuh_cdc_umount_cb(idx); // invoke callback - // Invoke application callback - tuh_cdc_umount_cb(idx); - - p_cdc->daddr = 0; + p_cdc->daddr = 0; p_cdc->bInterfaceNumber = 0; p_cdc->mounted = false; tu_edpt_stream_close(&p_cdc->stream.tx); @@ -696,13 +690,12 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t TU_ASSERT(p_cdc); if (ep_addr == p_cdc->stream.tx.ep_addr) { - // invoke tx complete callback to possibly refill tx fifo - tuh_cdc_tx_complete_cb(idx); + tuh_cdc_tx_complete_cb(idx); // invoke transmit complete callback if (0 == tu_edpt_stream_write_xfer(daddr, &p_cdc->stream.tx)) { // If there is no data left, a ZLP should be sent if: // - xferred_bytes is multiple of EP Packet size and not zero - tu_edpt_stream_write_zlp_if_needed(daddr, &p_cdc->stream.tx, xferred_bytes); + (void)tu_edpt_stream_write_zlp_if_needed(daddr, &p_cdc->stream.tx, xferred_bytes); } } else if (ep_addr == p_cdc->stream.rx.ep_addr) { #if CFG_TUH_CDC_FTDI @@ -718,7 +711,6 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t #endif { tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); - tuh_cdc_rx_cb(idx); // invoke receive callback } @@ -727,7 +719,7 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t } else if (ep_addr == p_cdc->ep_notif) { // TODO handle notification endpoint } else { - TU_ASSERT(false); + return false; } return true; @@ -736,20 +728,17 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t //--------------------------------------------------------------------+ // Enumeration //--------------------------------------------------------------------+ - static bool open_ep_stream_pair(cdch_interface_t *p_cdc, tusb_desc_endpoint_t const *desc_ep) { for (size_t i = 0; i < 2; i++) { TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); TU_ASSERT(tuh_edpt_open(p_cdc->daddr, desc_ep)); + tu_edpt_stream_t *stream = + (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) ? &p_cdc->stream.rx : &p_cdc->stream.tx; + tu_edpt_stream_open(stream, desc_ep); + tu_edpt_stream_clear(stream); - if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { - tu_edpt_stream_open(&p_cdc->stream.rx, desc_ep); - } else { - tu_edpt_stream_open(&p_cdc->stream.tx, desc_ep); - } - - desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(desc_ep); + desc_ep = (const tusb_desc_endpoint_t *)tu_desc_next(desc_ep); } return true; @@ -832,6 +821,7 @@ static void cdch_process_set_config(tuh_xfer_t *xfer) { } } +// return false if there is no active transfer static bool set_line_state_on_enum(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { enum { ENUM_SET_LINE_CODING = 0, diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index 79e7dfa71..b20903d68 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -404,15 +404,17 @@ uint16_t midid_open(uint8_t rhport, const tusb_desc_interface_t *desc_itf, uint1 const uint8_t ep_addr = ((const tusb_desc_endpoint_t *)p_desc)->bEndpointAddress; if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { - tu_edpt_stream_open(&p_midi->ep_stream.tx, desc_ep); - tu_edpt_stream_clear(&p_midi->ep_stream.tx); + tu_edpt_stream_t *stream_tx = &p_midi->ep_stream.tx; + tu_edpt_stream_open(stream_tx, desc_ep); + tu_edpt_stream_clear(stream_tx); } else { - tu_edpt_stream_open(&p_midi->ep_stream.rx, desc_ep); - tu_edpt_stream_clear(&p_midi->ep_stream.rx); - TU_ASSERT(tu_edpt_stream_read_xfer(rhport, &p_midi->ep_stream.rx) > 0, 0); // prepare to receive data + tu_edpt_stream_t *stream_rx = &p_midi->ep_stream.rx; + tu_edpt_stream_open(stream_rx, desc_ep); + tu_edpt_stream_clear(stream_rx); + TU_ASSERT(tu_edpt_stream_read_xfer(rhport, stream_rx) > 0, 0); // prepare to receive data } - p_desc = tu_desc_next(p_desc); // skip CS Endpoint descriptor + p_desc = tu_desc_next(p_desc); // skip CS Endpoint descriptor found_ep++; } diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 8b78fe945..07062875c 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -59,9 +59,6 @@ typedef struct { uint8_t iInterface; uint8_t itf_count; // number of interface including Audio Control + MIDI streaming - uint8_t ep_in; // IN endpoint address - uint8_t ep_out; // OUT endpoint address - uint8_t rx_cable_count; // IN endpoint CS descriptor bNumEmbMIDIJack value uint8_t tx_cable_count; // OUT endpoint CS descriptor bNumEmbMIDIJack value @@ -147,8 +144,6 @@ void midih_close(uint8_t daddr) { TU_LOG_DRV(" MIDI close addr = %u index = %u\r\n", daddr, idx); tuh_midi_umount_cb(idx); - p_midi->ep_in = 0; - p_midi->ep_out = 0; p_midi->bInterfaceNumber = 0; p_midi->rx_cable_count = 0; p_midi->tx_cable_count = 0; @@ -169,23 +164,25 @@ bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint const uint8_t idx = get_idx_by_ep_addr(dev_addr, ep_addr); TU_VERIFY(idx < CFG_TUH_MIDI); midih_interface_t *p_midi = &_midi_host[idx]; + tu_edpt_stream_t *ep_str_rx = &p_midi->ep_stream.rx; + tu_edpt_stream_t *ep_str_tx = &p_midi->ep_stream.tx; - if (ep_addr == p_midi->ep_stream.rx.ep_addr) { + if (ep_addr == ep_str_rx->ep_addr) { // receive new data, put it into FIFO and invoke callback if available // Note: some devices send back all zero packets even if there is no data ready - if (xferred_bytes && !tu_mem_is_zero(p_midi->ep_stream.rx.ep_buf, xferred_bytes)) { - tu_edpt_stream_read_xfer_complete(&p_midi->ep_stream.rx, xferred_bytes); + if (xferred_bytes && !tu_mem_is_zero(ep_str_rx->ep_buf, xferred_bytes)) { + tu_edpt_stream_read_xfer_complete(ep_str_rx, xferred_bytes); tuh_midi_rx_cb(idx, xferred_bytes); } - tu_edpt_stream_read_xfer(dev_addr, &p_midi->ep_stream.rx); // prepare for next transfer - } else if (ep_addr == p_midi->ep_stream.tx.ep_addr) { + tu_edpt_stream_read_xfer(dev_addr, ep_str_rx); // prepare for next transfer + } else if (ep_addr == ep_str_tx->ep_addr) { tuh_midi_tx_cb(idx, xferred_bytes); - if (0 == tu_edpt_stream_write_xfer(dev_addr, &p_midi->ep_stream.tx)) { + if (0 == tu_edpt_stream_write_xfer(dev_addr, ep_str_tx)) { // If there is no data left, a ZLP should be sent if // xferred_bytes is multiple of EP size and not zero - tu_edpt_stream_write_zlp_if_needed(dev_addr, &p_midi->ep_stream.tx, xferred_bytes); + tu_edpt_stream_write_zlp_if_needed(dev_addr, ep_str_tx, xferred_bytes); } } @@ -295,21 +292,20 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d const midi_desc_cs_endpoint_t *p_csep = (const midi_desc_cs_endpoint_t *) p_desc; TU_LOG_DRV(" Endpoint and CS_Endpoint descriptor %02x\r\n", p_ep->bEndpointAddress); + tu_edpt_stream_t *ep_stream; if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) { - p_midi->ep_out = p_ep->bEndpointAddress; p_midi->tx_cable_count = p_csep->bNumEmbMIDIJack; desc_cb.desc_epout = p_ep; - - TU_ASSERT(tuh_edpt_open(dev_addr, p_ep)); - tu_edpt_stream_open(&p_midi->ep_stream.tx, p_ep); + ep_stream = &p_midi->ep_stream.tx; } else { - p_midi->ep_in = p_ep->bEndpointAddress; p_midi->rx_cable_count = p_csep->bNumEmbMIDIJack; - desc_cb.desc_epin = p_ep; - - TU_ASSERT(tuh_edpt_open(dev_addr, p_ep)); - tu_edpt_stream_open(&p_midi->ep_stream.rx, p_ep); + desc_cb.desc_epin = p_ep; + ep_stream = &p_midi->ep_stream.rx; } + TU_ASSERT(tuh_edpt_open(dev_addr, p_ep)); + tu_edpt_stream_open(ep_stream, p_ep); + tu_edpt_stream_clear(ep_stream); + break; } @@ -379,8 +375,14 @@ bool tuh_midi_itf_get_info(uint8_t idx, tuh_itf_info_t* info) { desc->bDescriptorType = TUSB_DESC_INTERFACE; desc->bInterfaceNumber = p_midi->bInterfaceNumber; - desc->bAlternateSetting = 0; - desc->bNumEndpoints = (uint8_t)((p_midi->ep_in != 0 ? 1:0) + (p_midi->ep_out != 0 ? 1:0)); + desc->bAlternateSetting = 0; + desc->bNumEndpoints = 0; + if (tu_edpt_stream_is_opened(&p_midi->ep_stream.tx)) { + desc->bNumEndpoints++; + } + if (tu_edpt_stream_is_opened(&p_midi->ep_stream.rx)) { + desc->bNumEndpoints++; + } desc->bInterfaceClass = TUSB_CLASS_AUDIO; desc->bInterfaceSubClass = AUDIO_SUBCLASS_MIDI_STREAMING; desc->bInterfaceProtocol = 0; diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h index 7aa42a2d7..f377d5272 100644 --- a/src/common/tusb_common.h +++ b/src/common/tusb_common.h @@ -354,7 +354,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_subtype(void const* desc) { return ((uint8_t const*) desc)[DESC_OFFSET_SUBTYPE]; } -TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_in_bounds(uint8_t const* p_desc, uint8_t const* desc_end) { +TU_ATTR_ALWAYS_INLINE static inline bool tu_desc_in_bounds(const uint8_t *p_desc, const uint8_t *desc_end) { if (p_desc >= desc_end) { return false; } diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index f82f87b6f..be1264a71 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -120,7 +120,6 @@ TU_ATTR_ALWAYS_INLINE static inline bool tu_edpt_stream_empty(tu_edpt_stream_t * return tu_fifo_empty(&s->ff); } - //--------------------------------------------------------------------+ // Stream Write //--------------------------------------------------------------------+ diff --git a/src/tusb.c b/src/tusb.c index df33f2680..6fb5309ab 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -517,7 +517,7 @@ uint32_t tu_edpt_stream_read_xfer(uint8_t hwid, tu_edpt_stream_t* s) { } uint32_t tu_edpt_stream_read(uint8_t hwid, tu_edpt_stream_t* s, void* buffer, uint32_t bufsize) { - uint32_t num_read = tu_fifo_read_n(&s->ff, buffer, (uint16_t) bufsize); + const uint32_t num_read = tu_fifo_read_n(&s->ff, buffer, (uint16_t)bufsize); tu_edpt_stream_read_xfer(hwid, s); return num_read; } -- cgit v1.3.1 From 2b07fa6e6a5376b6a9d1c4dd39b61a96cd9e0138 Mon Sep 17 00:00:00 2001 From: Ha Thach Date: Thu, 13 Nov 2025 12:47:36 +0700 Subject: Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/class/cdc/cdc_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/class') diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 80fa81d99..babb89952 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -290,7 +290,7 @@ void cdcd_init(void) { } bool cdcd_deinit(void) { - for(uint8_t i=0; istream.rx); tu_edpt_stream_deinit(&p_cdc->stream.tx); @@ -305,7 +305,7 @@ void cdcd_reset(uint8_t rhport) { cdcd_interface_t* p_cdc = &_cdcd_itf[i]; tu_memclr(p_cdc, ITF_MEM_RESET_SIZE); - tu_fifo_set_overwritable(&p_cdc->stream.tx.ff, _cdcd_cfg.tx_overwritabe_if_not_connected); // // back to default + tu_fifo_set_overwritable(&p_cdc->stream.tx.ff, _cdcd_cfg.tx_overwritabe_if_not_connected); // back to default tu_edpt_stream_close(&p_cdc->stream.rx); tu_edpt_stream_close(&p_cdc->stream.tx); } -- cgit v1.3.1 From 1df116adfc70bb6d86f6046b46560d5c42762c28 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 19 Nov 2025 11:56:53 +0700 Subject: clean up --- examples/device/dfu/src/main.c | 99 +++++------ examples/device/dfu/src/usb_descriptors.c | 190 ++++++++++------------ examples/device/dfu_runtime/src/usb_descriptors.c | 58 ++++--- src/class/dfu/dfu_device.c | 12 +- 4 files changed, 173 insertions(+), 186 deletions(-) (limited to 'src/class') diff --git a/examples/device/dfu/src/main.c b/examples/device/dfu/src/main.c index 43e0af9a5..77632bf1a 100644 --- a/examples/device/dfu/src/main.c +++ b/examples/device/dfu/src/main.c @@ -23,7 +23,7 @@ * */ - /* +/* * After device is enumerated in dfu mode run the following commands * * To transfer firmware from host to device (best to test with text file) @@ -48,21 +48,18 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF PROTYPES //--------------------------------------------------------------------+ -const char* upload_image[2]= -{ - "Hello world from TinyUSB DFU! - Partition 0", - "Hello world from TinyUSB DFU! - Partition 1" -}; +const char *upload_image[2] = {"Hello world from TinyUSB DFU! - Partition 0", + "Hello world from TinyUSB DFU! - Partition 1"}; /* Blink pattern * - 250 ms : device not mounted * - 1000 ms : device mounted * - 2500 ms : device is suspended */ -enum { +enum { BLINK_NOT_MOUNTED = 250, - BLINK_MOUNTED = 1000, - BLINK_SUSPENDED = 2500, + BLINK_MOUNTED = 1000, + BLINK_SUSPENDED = 2500, }; static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; @@ -70,21 +67,16 @@ static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; void led_blinking_task(void); /*------------- MAIN -------------*/ -int main(void) -{ +int main(void) { board_init(); // init device stack on configured roothub port - tusb_rhport_init_t dev_init = { - .role = TUSB_ROLE_DEVICE, - .speed = TUSB_SPEED_AUTO - }; + tusb_rhport_init_t dev_init = {.role = TUSB_ROLE_DEVICE, .speed = TUSB_SPEED_AUTO}; tusb_init(BOARD_TUD_RHPORT, &dev_init); board_init_after_tusb(); - while (1) - { + while (1) { tud_task(); // tinyusb device task led_blinking_task(); } @@ -95,29 +87,25 @@ int main(void) //--------------------------------------------------------------------+ // Invoked when device is mounted -void tud_mount_cb(void) -{ +void tud_mount_cb(void) { blink_interval_ms = BLINK_MOUNTED; } // Invoked when device is unmounted -void tud_umount_cb(void) -{ +void tud_umount_cb(void) { blink_interval_ms = BLINK_NOT_MOUNTED; } // Invoked when usb bus is suspended // remote_wakeup_en : if host allow us to perform remote wakeup // Within 7ms, device must draw an average of current less than 2.5 mA from bus -void tud_suspend_cb(bool remote_wakeup_en) -{ - (void) remote_wakeup_en; +void tud_suspend_cb(bool remote_wakeup_en) { + (void)remote_wakeup_en; blink_interval_ms = BLINK_SUSPENDED; } // Invoked when usb bus is resumed -void tud_resume_cb(void) -{ +void tud_resume_cb(void) { blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED; } @@ -129,19 +117,17 @@ void tud_resume_cb(void) // Invoked right before tud_dfu_download_cb() (state=DFU_DNBUSY) or tud_dfu_manifest_cb() (state=DFU_MANIFEST) // Application return timeout in milliseconds (bwPollTimeout) for the next download/manifest operation. // During this period, USB host won't try to communicate with us. -uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state) -{ - if ( state == DFU_DNBUSY ) - { +uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state) { + if (state == DFU_DNBUSY) { // For this example // - Atl0 Flash is fast : 1 ms // - Alt1 EEPROM is slow: 100 ms return (alt == 0) ? 1 : 100; - } - else if (state == DFU_MANIFEST) - { + } else if (state == DFU_MANIFEST) { // since we don't buffer entire image and do any flashing in manifest stage return 0; + } else { + // nothing to do } return 0; @@ -150,15 +136,13 @@ uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state) // Invoked when received DFU_DNLOAD (wLength>0) following by DFU_GETSTATUS (state=DFU_DNBUSY) requests // This callback could be returned before flashing op is complete (async). // Once finished flashing, application must call tud_dfu_finish_flashing() -void tud_dfu_download_cb(uint8_t alt, uint16_t block_num, uint8_t const* data, uint16_t length) -{ - (void) alt; - (void) block_num; +void tud_dfu_download_cb(uint8_t alt, uint16_t block_num, const uint8_t *data, uint16_t length) { + (void)alt; + (void)block_num; //printf("\r\nReceived Alt %u BlockNum %u of length %u\r\n", alt, wBlockNum, length); - for(uint16_t i=0; ibmRequestType_bit.type) { - case TUSB_REQ_TYPE_VENDOR: - switch (request->bRequest) { - case VENDOR_REQUEST_MICROSOFT: - if (request->wIndex == 7) { - return tud_control_xfer(rhport, request, (void *) (uintptr_t) desc_ms_os_20, MS_OS_20_DESC_LEN); - } else { - return false; - } - - default: - break; - } - break; + if (stage != CONTROL_STAGE_SETUP) { + return true; + } - default: - break; + if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR) { + if (request->bRequest == VENDOR_REQUEST_MICROSOFT) { + if (request->wIndex == 7) { + return tud_control_xfer(rhport, request, (void *)(uintptr_t)desc_ms_os_20, MS_OS_20_DESC_LEN); + } else { + return false; + } + } } // stall unknown request @@ -208,21 +196,21 @@ enum { }; // array of pointer to string descriptors -static char const *string_desc_arr[] = { - (const char[]){0x09, 0x04},// 0: is supported language is English (0x0409) - "TinyUSB", // 1: Manufacturer - "TinyUSB Device", // 2: Product - NULL, // 3: Serials will use unique ID if possible - "FLASH", // 4: DFU Partition 1 - "EEPROM", // 5: DFU Partition 2 +static const char *string_desc_arr[] = { + (const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409) + "TinyUSB", // 1: Manufacturer + "TinyUSB Device", // 2: Product + NULL, // 3: Serials will use unique ID if possible + "FLASH", // 4: DFU Partition 1 + "EEPROM", // 5: DFU Partition 2 }; static uint16_t _desc_str[32 + 1]; // Invoked when received GET STRING DESCRIPTOR request // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete -uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { - (void) langid; +const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { + (void)langid; size_t chr_count; switch (index) { @@ -246,8 +234,8 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { const char *str = string_desc_arr[index]; // Cap at max char - chr_count = strlen(str); - size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type + chr_count = strlen(str); + const size_t max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type if (chr_count > max_count) { chr_count = max_count; } @@ -260,7 +248,7 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { } // first byte is length (including header), second byte is string type - _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2)); + _desc_str[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * chr_count + 2)); return _desc_str; } diff --git a/examples/device/dfu_runtime/src/usb_descriptors.c b/examples/device/dfu_runtime/src/usb_descriptors.c index 6a0a46b94..8fa078da2 100644 --- a/examples/device/dfu_runtime/src/usb_descriptors.c +++ b/examples/device/dfu_runtime/src/usb_descriptors.c @@ -32,9 +32,8 @@ * Auto ProductID layout's Bitmap: * [MSB] HID | MSC | CDC [LSB] */ -#define PID_MAP(itf, n) ((CFG_TUD_##itf) ? (1 << (n)) : 0) -#define USB_PID (0x4000 | PID_MAP(CDC, 0) | PID_MAP(MSC, 1) | PID_MAP(HID, 2) | \ - PID_MAP(MIDI, 3) | PID_MAP(VENDOR, 4) ) +#define PID_MAP(itf, n) ((CFG_TUD_##itf) ? (1 << (n)) : 0) +#define USB_PID (0x4000 | PID_MAP(CDC, 0) | PID_MAP(MSC, 1) | PID_MAP(HID, 2) | PID_MAP(MIDI, 3) | PID_MAP(VENDOR, 4)) //--------------------------------------------------------------------+ // Device Descriptors @@ -108,33 +107,30 @@ uint8_t const *tud_descriptor_configuration_cb(uint8_t index) { //--------------------------------------------------------------------+ /* Microsoft OS 2.0 registry property descriptor -Per MS requirements https://msdn.microsoft.com/en-us/library/windows/hardware/hh450799(v=vs.85).aspx -device should create DeviceInterfaceGUIDs. It can be done by driver and -in case of real PnP solution device should expose MS "Microsoft OS 2.0 -registry property descriptor". Such descriptor can insert any record -into Windows registry per device/configuration/interface. In our case it -will insert "DeviceInterfaceGUIDs" multistring property. -GUID is freshly generated and should be OK to use. -https://developers.google.com/web/fundamentals/native-hardware/build-for-webusb/ -(Section Microsoft OS compatibility descriptors) + Per MS requirements https://msdn.microsoft.com/en-us/library/windows/hardware/hh450799(v=vs.85).aspx + device should create DeviceInterfaceGUIDs. It can be done by driver and + in case of real PnP solution device should expose MS "Microsoft OS 2.0 + registry property descriptor". Such descriptor can insert any record + into Windows registry per device/configuration/interface. In our case it + will insert "DeviceInterfaceGUIDs" multistring property. + GUID is freshly generated and should be OK to use. + https://developers.google.com/web/fundamentals/native-hardware/build-for-webusb/ + (Section Microsoft OS compatibility descriptors) */ #define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN) - #define MS_OS_20_DESC_LEN 0xA2 - #define VENDOR_REQUEST_MICROSOFT 1 // BOS Descriptor is required for webUSB -uint8_t const desc_bos[] = { - // total length, number of device caps - TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 1), +const uint8_t desc_bos[] = { + // total length, number of device caps + TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 1), - // Microsoft OS 2.0 descriptor - TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, 1) -}; + // Microsoft OS 2.0 descriptor + TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, 1)}; -uint8_t const *tud_descriptor_bos_cb(void) { +const uint8_t *tud_descriptor_bos_cb(void) { return desc_bos; } @@ -170,6 +166,16 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ return true; } + if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR) { + if (request->bRequest == VENDOR_REQUEST_MICROSOFT) { + if (request->wIndex == 7) { + return tud_control_xfer(rhport, request, (void *)(uintptr_t)desc_ms_os_20, MS_OS_20_DESC_LEN); + } else { + return false; + } + } + } + switch (request->bmRequestType_bit.type) { case TUSB_REQ_TYPE_VENDOR: switch (request->bRequest) { @@ -218,8 +224,8 @@ static uint16_t _desc_str[32 + 1]; // Invoked when received GET STRING DESCRIPTOR request // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete -uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { - (void) langid; +const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { + (void)langid; size_t chr_count; switch (index) { @@ -243,8 +249,8 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { const char *str = string_desc_arr[index]; // Cap at max char - chr_count = strlen(str); - size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type + chr_count = strlen(str); + const size_t max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type if (chr_count > max_count) { chr_count = max_count; } @@ -257,7 +263,7 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { } // first byte is length (including header), second byte is string type - _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2)); + _desc_str[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * chr_count + 2)); return _desc_str; } diff --git a/src/class/dfu/dfu_device.c b/src/class/dfu/dfu_device.c index 24b037ebb..ffe5941e8 100644 --- a/src/class/dfu/dfu_device.c +++ b/src/class/dfu/dfu_device.c @@ -251,6 +251,8 @@ bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control tud_control_status(rhport, request); } else if (stage == CONTROL_STAGE_ACK) { tud_dfu_detach_cb(); + } else { + // nothing to do } break; @@ -273,6 +275,8 @@ bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control tud_control_status(rhport, request); } else if (stage == CONTROL_STAGE_ACK) { tud_dfu_abort_cb(_dfu_ctx.alt); + } else { + // nothing to do } break; @@ -301,7 +305,7 @@ bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control _dfu_ctx.block = request->wValue; _dfu_ctx.length = request->wLength; - if (request->wLength) { + if (request->wLength > 0) { // Download with payload -> transition to DOWNLOAD SYNC _dfu_ctx.state = DFU_DNLOAD_SYNC; return tud_control_xfer(rhport, request, _transfer_buf, request->wLength); @@ -350,6 +354,8 @@ void tud_dfu_finish_flashing(uint8_t status) { _dfu_ctx.state = (_dfu_ctx.attrs & DFU_ATTR_MANIFESTATION_TOLERANT) ? DFU_MANIFEST_SYNC : DFU_MANIFEST_WAIT_RESET; + } else { + // nothing to do } } else { // failed while flashing, move to dfuError @@ -380,6 +386,8 @@ static bool process_download_get_status(uint8_t rhport, uint8_t stage, const tus } else { _dfu_ctx.state = DFU_DNLOAD_IDLE; } + } else { + // nothing to do } return true; @@ -407,6 +415,8 @@ static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, const tus } else { _dfu_ctx.state = DFU_IDLE; } + } else { + // nothing to do } return true; -- cgit v1.3.1 From b2dc419270d17f100ec04cd18e764fe66d298f77 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 19 Nov 2025 13:36:32 +0700 Subject: rename CFG_TUD_ENDPOINT0_BUFSIZE to make it more consistent use uint8_t for dfu state and status to reduce size --- src/class/dfu/dfu_device.c | 10 ++++------ src/device/usbd_control.c | 8 ++++---- src/tusb_option.h | 4 ++-- 3 files changed, 10 insertions(+), 12 deletions(-) (limited to 'src/class') diff --git a/src/class/dfu/dfu_device.c b/src/class/dfu/dfu_device.c index ffe5941e8..d3cc53918 100644 --- a/src/class/dfu/dfu_device.c +++ b/src/class/dfu/dfu_device.c @@ -50,19 +50,17 @@ typedef struct { uint8_t attrs; uint8_t alt; + uint8_t state; + uint8_t status; - dfu_state_t state; - dfu_status_t status; - - bool flashing_in_progress; + bool flashing_in_progress; uint16_t block; uint16_t length; } dfu_state_ctx_t; -// Only a single dfu state is allowed static dfu_state_ctx_t _dfu_ctx; -CFG_TUD_MEM_ALIGN uint8_t _transfer_buf[CFG_TUD_DFU_XFER_BUFSIZE]; +TU_ATTR_ALIGNED(4) uint8_t _transfer_buf[CFG_TUD_DFU_XFER_BUFSIZE]; static void reset_state(void) { _dfu_ctx.state = DFU_IDLE; diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c index 745530f69..996e7387f 100644 --- a/src/device/usbd_control.c +++ b/src/device/usbd_control.c @@ -60,7 +60,7 @@ typedef struct { static usbd_control_xfer_t _ctrl_xfer; CFG_TUD_MEM_SECTION static struct { - TUD_EPBUF_DEF(buf, CFG_TUD_EP0_BUFSIZE); + TUD_EPBUF_DEF(buf, CFG_TUD_ENDPOINT0_BUFSIZE); } _ctrl_epbuf; //--------------------------------------------------------------------+ @@ -88,13 +88,13 @@ bool tud_control_status(uint8_t rhport, const tusb_control_request_t* request) { // Each transaction has up to Endpoint0's max packet size. // This function can also transfer an zero-length packet static bool data_stage_xact(uint8_t rhport) { - const uint16_t xact_len = tu_min16(_ctrl_xfer.data_len - _ctrl_xfer.total_xferred, CFG_TUD_EP0_BUFSIZE); + const uint16_t xact_len = tu_min16(_ctrl_xfer.data_len - _ctrl_xfer.total_xferred, CFG_TUD_ENDPOINT0_BUFSIZE); uint8_t ep_addr = EDPT_CTRL_OUT; if (_ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN) { ep_addr = EDPT_CTRL_IN; if (0u != xact_len) { - TU_VERIFY(0 == tu_memcpy_s(_ctrl_epbuf.buf, CFG_TUD_EP0_BUFSIZE, _ctrl_xfer.buffer, xact_len)); + TU_VERIFY(0 == tu_memcpy_s(_ctrl_epbuf.buf, CFG_TUD_ENDPOINT0_BUFSIZE, _ctrl_xfer.buffer, xact_len)); } } @@ -179,7 +179,7 @@ bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, // Data Stage is complete when all request's length are transferred or // a short packet is sent including zero-length packet. if ((_ctrl_xfer.request.wLength == _ctrl_xfer.total_xferred) || - (xferred_bytes < CFG_TUD_EP0_BUFSIZE)) { + (xferred_bytes < CFG_TUD_ENDPOINT0_BUFSIZE)) { // DATA stage is complete bool is_ok = true; diff --git a/src/tusb_option.h b/src/tusb_option.h index 4937b2502..eed14214d 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -485,8 +485,8 @@ #define CFG_TUD_ENDPOINT0_SIZE 64 #endif -#ifndef CFG_TUD_EP0_BUFSIZE - #define CFG_TUD_EP0_BUFSIZE CFG_TUD_ENDPOINT0_SIZE +#ifndef CFG_TUD_ENDPOINT0_BUFSIZE + #define CFG_TUD_ENDPOINT0_BUFSIZE CFG_TUD_ENDPOINT0_SIZE #endif #ifndef CFG_TUD_INTERFACE_MAX -- cgit v1.3.1