diff options
| author | HiFiPhile <[email protected]> | 2025-11-19 22:05:07 +0100 |
|---|---|---|
| committer | HiFiPhile <[email protected]> | 2025-11-19 22:05:07 +0100 |
| commit | 85adf694e659bde41b34e2f585cb2db552279064 (patch) | |
| tree | 6445badf0b427556fd47fb3d7b682bb8b439039e /src/class | |
| parent | 2f0a35f21af4c09154d6b4b5b118325af8990e51 (diff) | |
| parent | 790c7a0d7a6099e88a0bf6bbc341504c8bdaa974 (diff) | |
Merge remote-tracking branch 'tinyusb/master' into copilot/fix-dcd-edpt-xfer-issue
Signed-off-by: HiFiPhile <[email protected]>
Diffstat (limited to 'src/class')
| -rw-r--r-- | src/class/cdc/cdc_device.c | 392 | ||||
| -rw-r--r-- | src/class/cdc/cdc_host.c | 50 | ||||
| -rw-r--r-- | src/class/dfu/dfu_device.c | 32 | ||||
| -rw-r--r-- | src/class/midi/midi_device.c | 509 | ||||
| -rw-r--r-- | src/class/midi/midi_device.h | 130 | ||||
| -rw-r--r-- | src/class/midi/midi_host.c | 48 | ||||
| -rw-r--r-- | src/class/vendor/vendor_device.c | 19 | ||||
| -rw-r--r-- | src/class/video/video_device.c | 22 | ||||
| -rw-r--r-- | src/class/video/video_device.h | 20 |
9 files changed, 531 insertions, 691 deletions
diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index bf631908f..9e62c6509 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); @@ -81,110 +76,100 @@ typedef struct { } 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, false); - } 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()); + 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); + return in_opened && out_opened; } bool tud_cdc_n_connected(uint8_t itf) { + TU_VERIFY(itf < CFG_TUD_CDC); + TU_VERIFY(tud_ready()); // DTR (bit 0) active is considered as connected - return tud_ready() && tu_bit_test(_cdcd_itf[itf].line_state, 0); + return tu_bit_test(_cdcd_itf[itf].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 +185,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 +204,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 +212,53 @@ 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); + 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) { - 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); + return tu_edpt_stream_peek(&_cdcd_itf[itf].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, false), 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 +267,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 +278,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; i<CFG_TUD_CDC; i++) { + for (uint8_t i = 0; i < CFG_TUD_CDC; i++) { cdcd_interface_t* p_cdc = &_cdcd_itf[i]; - const osal_mutex_t mutex_rd = p_cdc->rx_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 +303,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 (uint16_t)(p_desc - (const uint8_t *)itf_desc); } // Invoked when a control transfer occurred on an interface of this class @@ -449,7 +403,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 +438,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 +459,6 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_requ } else { // nothing to do } - break; default: @@ -518,58 +469,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, false)); - } - } + 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/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/dfu/dfu_device.c b/src/class/dfu/dfu_device.c index 0d2b63b57..d3cc53918 100644 --- a/src/class/dfu/dfu_device.c +++ b/src/class/dfu/dfu_device.c @@ -50,21 +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_SECTION static struct { - TUD_EPBUF_DEF(transfer_buf, CFG_TUD_DFU_XFER_BUFSIZE); -} _dfu_epbuf; +TU_ATTR_ALIGNED(4) uint8_t _transfer_buf[CFG_TUD_DFU_XFER_BUFSIZE]; static void reset_state(void) { _dfu_ctx.state = DFU_IDLE; @@ -253,6 +249,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; @@ -275,6 +273,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; @@ -283,10 +283,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; @@ -303,10 +303,10 @@ 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, _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; @@ -352,6 +352,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 @@ -378,10 +380,12 @@ 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; } + } else { + // nothing to do } return true; @@ -409,6 +413,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; diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index c4b4925d6..b20903d68 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -37,12 +37,18 @@ #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]; + // Endpoint stream + struct { + tu_edpt_stream_t tx; + tu_edpt_stream_t rx; - #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_ff_mutex; - osal_mutex_def_t tx_ff_mutex; - #endif + 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; -} - -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, false); - }else - { - // Release endpoint since we don't make any transfer - usbd_edpt_release(rhport, p_midi->ep_out); - } -} - + midid_interface_t *p_midi = &_midid_itf[itf]; -//--------------------------------------------------------------------+ -// 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, false), 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; i<CFG_TUD_MIDI; i++) { - midid_interface_t* midi = &_midid_itf[i]; - osal_mutex_t mutex_rd = midi->rx_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); + + tu_edpt_stream_clear(&p_midi->ep_stream.tx); + tu_edpt_stream_close(&p_midi->ep_stream.tx); + } +} - for(uint8_t i=0; i<CFG_TUD_MIDI; i++) - { - midid_interface_t* midi = &_midid_itf[i]; - tu_memclr(midi, ITF_MEM_RESET_SIZE); - tu_fifo_clear(&midi->rx_ff); - tu_fifo_clear(&midi->tx_ff); +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) { - uint16_t drv_len = 0; - uint8_t const * p_desc = (uint8_t const *)desc_itf; +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,48 @@ 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; idx<CFG_TUD_MIDI; idx++) { - if ( _midid_itf[idx].ep_in == 0 && _midid_itf[idx].ep_out == 0 ) { - p_midi = &_midid_itf[idx]; - break; - } - } - TU_ASSERT(p_midi); + uint8_t idx = find_midi_itf(0); // find unused interface + TU_ASSERT(idx < CFG_TUD_MIDI, 0); + midid_interface_t *p_midi = &_midid_itf[idx]; + p_midi->rhport = 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; + 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) - { - p_midi->ep_in = ep_addr; + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { + 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 { - p_midi->ep_out = ep_addr; + 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 } - // 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 +432,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); + tu_edpt_stream_t *ep_st_rx = &p_midi->ep_stream.rx; + tu_edpt_stream_t *ep_st_tx = &p_midi->ep_stream.tx; - // 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, false); - } - } + 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/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/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index 27724b194..7da4d2239 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); } } @@ -233,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/class/video/video_device.c b/src/class/video/video_device.c index 85e85e75e..b2375def9 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -214,6 +214,12 @@ 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, tud_video_payload_request_t* request) { + (void) ctl_idx; + (void) stm_idx; + (void) request; +} + //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ @@ -874,7 +880,16 @@ 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_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; if (!remaining) { @@ -1255,13 +1270,14 @@ 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 (NULL == buffer || 0 == bufsize) { + if (0 == 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 (NULL == stm || 0 == stm->desc.ep[0] || stm->buffer) { + if (NULL == stm || 0 == stm->desc.ep[0] || stm->bufsize) { return false; } if (stm->state == VS_STATE_PROBING) { diff --git a/src/class/video/video_device.h b/src/class/video/video_device.h index 2b41c3bfe..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 @@ -83,6 +93,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, tud_video_payload_request_t* request); + //--------------------------------------------------------------------+ // INTERNAL USBD-CLASS DRIVER API //--------------------------------------------------------------------+ |
