From 4f0369508450883504e377b40aaec8860c8cb256 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 14 Dec 2022 16:52:28 +0700 Subject: [PATCH 01/28] adding tuh_cdc_mount_cb/tuh_cdc_umount_cb start adding cdc_app.c to example --- examples/host/cdc_msc_hid/CMakeLists.txt | 3 +- examples/host/cdc_msc_hid/Makefile | 3 +- examples/host/cdc_msc_hid/src/cdc_app.c | 51 ++++++++++++++++++++++++ examples/host/cdc_msc_hid/src/main.c | 11 ++--- src/class/cdc/cdc_host.c | 12 ++++++ src/class/cdc/cdc_host.h | 17 +++++--- 6 files changed, 81 insertions(+), 16 deletions(-) create mode 100644 examples/host/cdc_msc_hid/src/cdc_app.c diff --git a/examples/host/cdc_msc_hid/CMakeLists.txt b/examples/host/cdc_msc_hid/CMakeLists.txt index d84457bc92..2e89817a56 100644 --- a/examples/host/cdc_msc_hid/CMakeLists.txt +++ b/examples/host/cdc_msc_hid/CMakeLists.txt @@ -14,8 +14,9 @@ add_executable(${PROJECT}) # Example source target_sources(${PROJECT} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/cdc_app.c ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c ) diff --git a/examples/host/cdc_msc_hid/Makefile b/examples/host/cdc_msc_hid/Makefile index ad28076a04..9adccfa3ad 100644 --- a/examples/host/cdc_msc_hid/Makefile +++ b/examples/host/cdc_msc_hid/Makefile @@ -7,7 +7,8 @@ INC += \ # Example source EXAMPLE_SOURCE = \ - src/hid_app.c \ + src/cdc_app.c \ + src/hid_app.c \ src/main.c \ src/msc_app.c \ diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c new file mode 100644 index 0000000000..29da02abc5 --- /dev/null +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -0,0 +1,51 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2022, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb.h" + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM DECLARATION +//--------------------------------------------------------------------+ + + +//------------- IMPLEMENTATION -------------// + +void cdc_app_task(void) +{ + +} + +void tuh_cdc_mount_cb(uint8_t dev_addr) +{ + (void) dev_addr; + printf("A CDC device is mounted\r\n"); +} + +void tuh_cdc_umount_cb(uint8_t dev_addr) +{ + (void) dev_addr; + printf("A CDC device is unmounted\r\n"); +} diff --git a/examples/host/cdc_msc_hid/src/main.c b/examples/host/cdc_msc_hid/src/main.c index d26e41e8df..465e457f70 100644 --- a/examples/host/cdc_msc_hid/src/main.c +++ b/examples/host/cdc_msc_hid/src/main.c @@ -35,7 +35,7 @@ //--------------------------------------------------------------------+ void led_blinking_task(void); -extern void cdc_task(void); +extern void cdc_app_task(void); extern void hid_app_task(void); /*------------- MAIN -------------*/ @@ -52,9 +52,9 @@ int main(void) { // tinyusb host task tuh_task(); - led_blinking_task(); - cdc_task(); + led_blinking_task(); + cdc_app_task(); hid_app_task(); } @@ -79,11 +79,6 @@ void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_i tuh_cdc_receive(dev_addr, serial_in_buffer, sizeof(serial_in_buffer), true); // waiting for next data } -void cdc_task(void) -{ - -} - //--------------------------------------------------------------------+ // TinyUSB Callbacks //--------------------------------------------------------------------+ diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index ee824cb4ed..aa3a7e1e5a 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -239,6 +239,8 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num) { (void) dev_addr; (void) itf_num; + + if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(dev_addr); return true; } @@ -254,6 +256,16 @@ void cdch_close(uint8_t dev_addr) TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); cdch_data_t * p_cdc = get_itf(dev_addr); + + // Invoke application callback + if (tuh_cdc_umount_cb) + { + if (p_cdc->ep_out || p_cdc->ep_in || p_cdc->ep_notif) + { + tuh_cdc_umount_cb(dev_addr); + } + } + tu_memclr(p_cdc, sizeof(cdch_data_t)); } diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 33dbd2efb4..c3b601b34f 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -34,13 +34,18 @@ #endif //--------------------------------------------------------------------+ -// CDC APPLICATION PUBLIC API +// Application API //--------------------------------------------------------------------+ -/** \ingroup ClassDriver_CDC Communication Device Class (CDC) - * \addtogroup CDC_Serial Serial - * @{ - * \defgroup CDC_Serial_Host Host - * @{ */ + + +//------------- Application Callback -------------// + +// Invoked when a device with CDC interface is mounted +TU_ATTR_WEAK void tuh_cdc_mount_cb(uint8_t dev_addr); + +// Invoked when a device with CDC interface is unmounted +TU_ATTR_WEAK void tuh_cdc_umount_cb(uint8_t dev_addr); + bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb); From f0c51eae44e4cd8f38fdba6469e49b1d98100d7c Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 14 Dec 2022 17:35:01 +0700 Subject: [PATCH 02/28] cdc check for bNumEndpoints before checking for endpoint descriptor --- src/class/cdc/cdc_host.c | 64 ++++++++++++++++++++++------------------ src/host/usbh.c | 3 +- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index aa3a7e1e5a..83fa1bf5e1 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -152,13 +152,43 @@ bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xf } //--------------------------------------------------------------------+ -// USBH-CLASS DRIVER API +// CLASS-USBH API //--------------------------------------------------------------------+ + void cdch_init(void) { tu_memclr(cdch_data, sizeof(cdch_data)); } +void cdch_close(uint8_t dev_addr) +{ + TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); + + cdch_data_t * p_cdc = get_itf(dev_addr); + + // Invoke application callback + if (tuh_cdc_umount_cb) + { + if (p_cdc->ep_out || p_cdc->ep_in || p_cdc->ep_notif) + { + tuh_cdc_umount_cb(dev_addr); + } + } + + tu_memclr(p_cdc, sizeof(cdch_data_t)); +} + +bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +{ + (void) ep_addr; + tuh_cdc_xfer_isr( dev_addr, event, 0, xferred_bytes ); + return true; +} + +//--------------------------------------------------------------------+ +// Enumeration +//--------------------------------------------------------------------+ + bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { (void) rhport; @@ -175,7 +205,7 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it p_cdc->itf_num = itf_desc->bInterfaceNumber; p_cdc->itf_protocol = itf_desc->bInterfaceProtocol; - //------------- Communication Interface -------------// + //------------- Control Interface -------------// uint16_t drv_len = tu_desc_len(itf_desc); uint8_t const * p_desc = tu_desc_next(itf_desc); @@ -192,9 +222,10 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it p_desc = tu_desc_next(p_desc); } - if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) + // Open notification endpoint of control interface if any + if (itf_desc->bNumEndpoints == 1) { - // notification endpoint + TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)); tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) ); @@ -244,29 +275,4 @@ bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num) return true; } -bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) -{ - (void) ep_addr; - tuh_cdc_xfer_isr( dev_addr, event, 0, xferred_bytes ); - return true; -} - -void cdch_close(uint8_t dev_addr) -{ - TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); - - cdch_data_t * p_cdc = get_itf(dev_addr); - - // Invoke application callback - if (tuh_cdc_umount_cb) - { - if (p_cdc->ep_out || p_cdc->ep_in || p_cdc->ep_notif) - { - tuh_cdc_umount_cb(dev_addr); - } - } - - tu_memclr(p_cdc, sizeof(cdch_data_t)); -} - #endif diff --git a/src/host/usbh.c b/src/host/usbh.c index ca42a523ca..b0cd62bac1 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1524,8 +1524,7 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur TU_ASSERT(drv_len >= sizeof(tusb_desc_interface_t)); // Find driver for this interface - uint8_t drv_id; - for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++) + for (uint8_t drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++) { usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id]; From f62f97395626f316f1670f1777a0a75877e8e773 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 14 Dec 2022 23:19:47 +0700 Subject: [PATCH 03/28] minor rename --- src/class/cdc/cdc_host.c | 51 +++++++++++++++++++++++++++++++++------- src/class/cdc/cdc_host.h | 26 +++++++++++++++----- src/class/hid/hid_host.c | 1 + src/tusb_option.h | 4 ++++ 4 files changed, 67 insertions(+), 15 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 83fa1bf5e1..9678b756c1 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -37,6 +37,7 @@ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ typedef struct { + // uint8_t daddr; uint8_t itf_num; uint8_t itf_protocol; @@ -46,21 +47,42 @@ typedef struct { cdc_acm_capability_t acm_capability; -} cdch_data_t; + // Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) + // uint8_t line_state; +#if 0 + + // FIFO + tu_fifo_t rx_ff; + tu_fifo_t tx_ff; + + uint8_t rx_ff_buf[CFG_TUH_CDC_RX_BUFSIZE]; + uint8_t tx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; + +#if CFG_FIFO_MUTEX + osal_mutex_def_t rx_ff_mutex; + osal_mutex_def_t tx_ff_mutex; +#endif + + // Endpoint Transfer buffer + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUH_CDC_EP_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUH_CDC_EP_BUFSIZE]; +#endif + +} cdch_interface_t; //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -static cdch_data_t cdch_data[CFG_TUH_DEVICE_MAX]; +static cdch_interface_t cdch_data[CFG_TUH_DEVICE_MAX]; -static inline cdch_data_t* get_itf(uint8_t dev_addr) +static inline cdch_interface_t* get_itf(uint8_t dev_addr) { return &cdch_data[dev_addr-1]; } bool tuh_cdc_mounted(uint8_t dev_addr) { - cdch_data_t* cdc = get_itf(dev_addr); + cdch_interface_t* cdc = get_itf(dev_addr); return cdc->ep_in && cdc->ep_out; } @@ -68,7 +90,7 @@ bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid) { if ( !tuh_cdc_mounted(dev_addr) ) return false; - cdch_data_t const * p_cdc = get_itf(dev_addr); + cdch_interface_t const * p_cdc = get_itf(dev_addr); switch (pipeid) { @@ -89,6 +111,17 @@ bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid) //--------------------------------------------------------------------+ // APPLICATION API (parameter validation needed) //--------------------------------------------------------------------+ + +uint32_t tuh_cdc_write(uint8_t dev_addr, void const* buffer, uint32_t bufsize) +{ + (void) dev_addr; + (void) buffer; + (void) bufsize; + + return 0; +} + + bool tuh_cdc_serial_is_mounted(uint8_t dev_addr) { // TODO consider all AT Command as serial candidate @@ -122,7 +155,7 @@ bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb) { - cdch_data_t const * p_cdc = get_itf(dev_addr); + cdch_interface_t const * p_cdc = get_itf(dev_addr); tusb_control_request_t const request = { @@ -164,7 +197,7 @@ void cdch_close(uint8_t dev_addr) { TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); - cdch_data_t * p_cdc = get_itf(dev_addr); + cdch_interface_t * p_cdc = get_itf(dev_addr); // Invoke application callback if (tuh_cdc_umount_cb) @@ -175,7 +208,7 @@ void cdch_close(uint8_t dev_addr) } } - tu_memclr(p_cdc, sizeof(cdch_data_t)); + tu_memclr(p_cdc, sizeof(cdch_interface_t)); } bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) @@ -200,7 +233,7 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass && 0xFF != itf_desc->bInterfaceProtocol); - cdch_data_t * p_cdc = get_itf(dev_addr); + cdch_interface_t * p_cdc = get_itf(dev_addr); p_cdc->itf_num = itf_desc->bInterfaceNumber; p_cdc->itf_protocol = itf_desc->bInterfaceProtocol; diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index c3b601b34f..ce1f0f3095 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -34,19 +34,24 @@ #endif //--------------------------------------------------------------------+ -// Application API +// Class Driver Configuration //--------------------------------------------------------------------+ -//------------- Application Callback -------------// +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ -// Invoked when a device with CDC interface is mounted -TU_ATTR_WEAK void tuh_cdc_mount_cb(uint8_t dev_addr); +bool tuh_cdc_mounted(uint8_t dev_addr); -// Invoked when a device with CDC interface is unmounted -TU_ATTR_WEAK void tuh_cdc_umount_cb(uint8_t dev_addr); +uint32_t tuh_cdc_write(uint8_t dev_addr, void const* buffer, uint32_t bufsize); +//uint32_t tuh_cdc_read(uint8_t dev_addr, void* buffer, uint32_t bufsize); +//--------------------------------------------------------------------+ +// Control Endpoint (Request) API +//--------------------------------------------------------------------+ +// Set Control Line State (DTR, RTS) bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb); static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb) @@ -59,6 +64,15 @@ static inline bool tuh_cdc_disconnect(uint8_t dev_addr, tuh_xfer_cb_t complete_c return tuh_cdc_set_control_line_state(dev_addr, false, false, complete_cb); } +//------------- Application Callback -------------// + +// Invoked when a device with CDC interface is mounted +TU_ATTR_WEAK void tuh_cdc_mount_cb(uint8_t dev_addr); + +// Invoked when a device with CDC interface is unmounted +TU_ATTR_WEAK void tuh_cdc_umount_cb(uint8_t dev_addr); + + /** \brief Check if device support CDC Serial interface or not * \param[in] dev_addr device address * \retval true if device supports diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index ca745464cb..504ddca1e2 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -62,6 +62,7 @@ typedef struct hidh_interface_t instances[CFG_TUH_HID]; } hidh_device_t; +CFG_TUSB_MEM_SECTION static hidh_device_t _hidh_dev[CFG_TUH_DEVICE_MAX]; //------------- Internal prototypes -------------// diff --git a/src/tusb_option.h b/src/tusb_option.h index 9ca6c794bd..69972c6304 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -256,6 +256,10 @@ typedef int make_iso_compilers_happy; // For backward compatible #define TUSB_OPT_HOST_ENABLED CFG_TUH_ENABLED +// highspeed support indicator +#define TUH_OPT_HIGH_SPEED (CFG_TUH_MAX_SPEED ? (CFG_TUH_MAX_SPEED & OPT_MODE_HIGH_SPEED) : TUP_RHPORT_HIGHSPEED) + + //--------------------------------------------------------------------+ // TODO move later //--------------------------------------------------------------------+ From bd1f7f86ce1b6e82c3942d545e984b74b050004e Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 15 Dec 2022 15:27:39 +0700 Subject: [PATCH 04/28] add common EPSIZE for bulk/iso in full and highspeed adding cdc host fifo tx/rx --- src/class/cdc/cdc_device.h | 1 - src/class/cdc/cdc_host.c | 71 +++++++++++++++++-------------------- src/class/cdc/cdc_host.h | 19 ++++++++++ src/common/tusb_types.h | 10 +++++- src/host/usbh_classdriver.h | 4 +++ 5 files changed, 64 insertions(+), 41 deletions(-) diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index fbc7162a36..f625a75549 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -27,7 +27,6 @@ #ifndef _TUSB_CDC_DEVICE_H_ #define _TUSB_CDC_DEVICE_H_ -#include "common/tusb_common.h" #include "cdc.h" //--------------------------------------------------------------------+ diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 9678b756c1..da8ad726b4 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -37,7 +37,7 @@ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ typedef struct { - // uint8_t daddr; + uint8_t daddr; uint8_t itf_num; uint8_t itf_protocol; @@ -49,7 +49,6 @@ typedef struct { // Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) // uint8_t line_state; -#if 0 // FIFO tu_fifo_t rx_ff; @@ -64,54 +63,48 @@ typedef struct { #endif // Endpoint Transfer buffer - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUH_CDC_EP_BUFSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUH_CDC_EP_BUFSIZE]; -#endif + CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUH_CDC_RX_EPSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUH_CDC_TX_EPSIZE]; } cdch_interface_t; //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -static cdch_interface_t cdch_data[CFG_TUH_DEVICE_MAX]; + +CFG_TUSB_MEM_SECTION +static cdch_interface_t cdch_data[CFG_TUH_CDC]; static inline cdch_interface_t* get_itf(uint8_t dev_addr) { - return &cdch_data[dev_addr-1]; -} + for(size_t i=0; iep_in && cdc->ep_out; + return NULL; } -bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid) +static cdch_interface_t* find_new_itf(void) { - if ( !tuh_cdc_mounted(dev_addr) ) return false; - - cdch_interface_t const * p_cdc = get_itf(dev_addr); - - switch (pipeid) + for(size_t i=0; iep_notif ); - - case CDC_PIPE_DATA_IN: - return usbh_edpt_busy(dev_addr, p_cdc->ep_in ); - - case CDC_PIPE_DATA_OUT: - return usbh_edpt_busy(dev_addr, p_cdc->ep_out ); - - default: - return false; + if (cdch_data[i].daddr == 0) return &cdch_data[i]; } + + return NULL; } //--------------------------------------------------------------------+ // APPLICATION API (parameter validation needed) //--------------------------------------------------------------------+ +bool tuh_cdc_mounted(uint8_t dev_addr) +{ + cdch_interface_t* p_cdc = get_itf(dev_addr); + return p_cdc != NULL; +} + uint32_t tuh_cdc_write(uint8_t dev_addr, void const* buffer, uint32_t bufsize) { (void) dev_addr; @@ -121,7 +114,6 @@ uint32_t tuh_cdc_write(uint8_t dev_addr, void const* buffer, uint32_t bufsize) return 0; } - bool tuh_cdc_serial_is_mounted(uint8_t dev_addr) { // TODO consider all AT Command as serial candidate @@ -156,6 +148,7 @@ bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb) { cdch_interface_t const * p_cdc = get_itf(dev_addr); + TU_VERIFY(p_cdc && p_cdc->acm_capability.support_line_request); tusb_control_request_t const request = { @@ -195,17 +188,13 @@ void cdch_init(void) void cdch_close(uint8_t dev_addr) { - TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, ); - cdch_interface_t * p_cdc = get_itf(dev_addr); + TU_VERIFY(p_cdc, ); // Invoke application callback if (tuh_cdc_umount_cb) { - if (p_cdc->ep_out || p_cdc->ep_in || p_cdc->ep_notif) - { - tuh_cdc_umount_cb(dev_addr); - } + tuh_cdc_umount_cb(dev_addr); } tu_memclr(p_cdc, sizeof(cdch_interface_t)); @@ -233,8 +222,10 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass && 0xFF != itf_desc->bInterfaceProtocol); - cdch_interface_t * p_cdc = get_itf(dev_addr); + cdch_interface_t * p_cdc = find_new_itf(); + TU_VERIFY(p_cdc); + p_cdc->daddr = dev_addr; p_cdc->itf_num = itf_desc->bInterfaceNumber; p_cdc->itf_protocol = itf_desc->bInterfaceProtocol; @@ -302,9 +293,11 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num) { - (void) dev_addr; (void) itf_num; - if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(dev_addr); + + // notify usbh that driver enumeration is complete + usbh_driver_set_config_complete(dev_addr, itf_num); + return true; } diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index ce1f0f3095..b2e75902d4 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -37,6 +37,25 @@ // Class Driver Configuration //--------------------------------------------------------------------+ +// RX FIFO size +#ifndef CFG_TUH_CDC_RX_BUFSIZE +#define CFG_TUH_CDC_RX_BUFSIZE USBH_EPSIZE_BULK_MAX +#endif + +// RX Endpoint size +#ifndef CFG_TUH_CDC_RX_EPSIZE +#define CFG_TUH_CDC_RX_EPSIZE USBH_EPSIZE_BULK_MAX +#endif + +// TX FIFO size +#ifndef CFG_TUH_CDC_TX_BUFSIZE +#define CFG_TUH_CDC_TX_BUFSIZE USBH_EPSIZE_BULK_MAX +#endif + +// TX Endpoint size +#ifndef CFG_TUH_CDC_TX_EPSIZE +#define CFG_TUH_CDC_TX_EPSIZE USBH_EPSIZE_BULK_MAX +#endif //--------------------------------------------------------------------+ // Application API diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index 1bfa7c7d12..c4c9d41330 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -69,6 +69,15 @@ typedef enum TUSB_DIR_IN_MASK = 0x80 }tusb_dir_t; +enum +{ + TUSB_EPSIZE_BULK_FS = 64, + TUSB_EPSIZE_BULK_HS= 512, + + TUSB_EPSIZE_ISO_FS_MAX = 1023, + TUSB_EPSIZE_ISO_HS_MAX = 1024, +}; + /// Isochronous End Point Attributes typedef enum { @@ -243,7 +252,6 @@ enum INTERFACE_INVALID_NUMBER = 0xff }; - typedef enum { MS_OS_20_SET_HEADER_DESCRIPTOR = 0x00, diff --git a/src/host/usbh_classdriver.h b/src/host/usbh_classdriver.h index c156afea04..7f72560c32 100644 --- a/src/host/usbh_classdriver.h +++ b/src/host/usbh_classdriver.h @@ -34,6 +34,10 @@ extern "C" { #endif +enum { + USBH_EPSIZE_BULK_MAX = (TUH_OPT_HIGH_SPEED ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS) +}; + //--------------------------------------------------------------------+ // Class Driver API //--------------------------------------------------------------------+ From 4811b3463ff20fb6eee551b42d66a6e74b411746 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 15 Dec 2022 17:16:19 +0700 Subject: [PATCH 05/28] stub --- src/class/cdc/cdc_host.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index da8ad726b4..cb0794fa3c 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -36,6 +36,14 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ + +//typedef struct { +// tu_fifo_t fifo; +// OSAL_MUTEX_DEF(ff_mutex); +// +// +//}usbh_edpt_stream_t; + typedef struct { uint8_t daddr; uint8_t itf_num; @@ -184,6 +192,13 @@ bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xf void cdch_init(void) { tu_memclr(cdch_data, sizeof(cdch_data)); + +// for(size_t i=0; i Date: Fri, 16 Dec 2022 23:54:21 +0700 Subject: [PATCH 06/28] correct cdc usbh_driver_set_config_complete() --- src/class/cdc/cdc_host.c | 32 +++++++++++++++++++++----------- src/host/usbh.c | 3 ++- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index cb0794fa3c..482ccf4beb 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -36,13 +36,24 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ +#if 0 +typedef struct { + tu_fifo_t ff; + OSAL_MUTEX_DEF(ff_mutex); +}tu_edpt_stream_t; -//typedef struct { -// tu_fifo_t fifo; -// OSAL_MUTEX_DEF(ff_mutex); -// -// -//}usbh_edpt_stream_t; +uint32_t tud_cdc_read_available (void); +uint32_t tud_cdc_read (void *buffer, uint32_t bufsize); +void tud_cdc_read_flush (void); +bool tud_cdc_peek (uint8_t *ui8); + +uint32_t tud_cdc_write (void const *buffer, uint32_t bufsize); +uint32_t tud_cdc_write_flush (void); +uint32_t tud_cdc_write_available (void); + +//-------------------------------------------------------- +tu_edpt_stream_write() +#endif typedef struct { uint8_t daddr; @@ -65,10 +76,8 @@ typedef struct { uint8_t rx_ff_buf[CFG_TUH_CDC_RX_BUFSIZE]; uint8_t tx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; -#if CFG_FIFO_MUTEX - osal_mutex_def_t rx_ff_mutex; - osal_mutex_def_t tx_ff_mutex; -#endif + OSAL_MUTEX_DEF(rx_ff_mutex); + OSAL_MUTEX_DEF(tx_ff_mutex); // Endpoint Transfer buffer CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUH_CDC_RX_EPSIZE]; @@ -311,7 +320,8 @@ bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num) if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(dev_addr); // notify usbh that driver enumeration is complete - usbh_driver_set_config_complete(dev_addr, itf_num); + // itf_num+1 to account for data interface as well + usbh_driver_set_config_complete(dev_addr, itf_num+1); return true; } diff --git a/src/host/usbh.c b/src/host/usbh.c index b0cd62bac1..4b278f2da0 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1570,7 +1570,8 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) for(itf_num++; itf_num < CFG_TUH_INTERFACE_MAX; itf_num++) { // continue with next valid interface - // TODO skip IAD binding interface such as CDCs + // IAD binding interface such as CDCs should return itf_num + 1 when complete + // with usbh_driver_set_config_complete() uint8_t const drv_id = dev->itf2drv[itf_num]; if (drv_id != DRVID_INVALID) { From 7004914d8c6c7d88908776eb153661b6b987e513 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 20 Dec 2022 12:06:59 +0700 Subject: [PATCH 07/28] fix hid host incorrect edpt release if failed to transmit add CDC_CONTROL_LINE_STATE_DTR/RTS, TUSB_INDEX_INVALID enum --- src/class/cdc/cdc.h | 10 ++++++++-- src/class/hid/hid_host.c | 2 +- src/common/tusb_types.h | 5 +++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index c428af8650..6a9669cf24 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -192,6 +192,12 @@ typedef enum CDC_REQUEST_MDLM_SEMANTIC_MODEL = 0x60, }cdc_management_request_t; +enum +{ + CDC_CONTROL_LINE_STATE_DTR = 0x01, + CDC_CONTROL_LINE_STATE_RTS = 0x02, +}; + //--------------------------------------------------------------------+ // Management Element Notification (Notification Endpoint) //--------------------------------------------------------------------+ @@ -390,8 +396,8 @@ TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct"); typedef struct TU_ATTR_PACKED { - uint16_t dte_is_present : 1; ///< Indicates to DCE if DTE is presentor not. This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR. - uint16_t half_duplex_carrier_control : 1; + uint16_t dtr : 1; + uint16_t rts : 1; uint16_t : 14; } cdc_line_control_state_t; diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 504ddca1e2..42b5e2f4eb 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -259,7 +259,7 @@ bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance) if ( !usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size) ) { - usbh_edpt_claim(dev_addr, hid_itf->ep_in); + usbh_edpt_release(dev_addr, hid_itf->ep_in); return false; } diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index c4c9d41330..32cdba450f 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -273,6 +273,11 @@ enum CONTROL_STAGE_ACK }; +enum +{ + TUSB_INDEX_INVALID = 0xff +}; + //--------------------------------------------------------------------+ // USB Descriptors //--------------------------------------------------------------------+ From 854e5222aea570a2be2201d8c460f54b87c9108a Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 00:26:46 +0700 Subject: [PATCH 08/28] finalizing cdc host, has a working read/write TODO: first character seems not to get echoed. set control line state seems to failed with LOG < 2 --- examples/host/cdc_msc_hid/src/main.c | 18 -- src/class/cdc/cdc_host.c | 458 +++++++++++++++++++++------ src/class/cdc/cdc_host.h | 84 +++-- 3 files changed, 419 insertions(+), 141 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/main.c b/examples/host/cdc_msc_hid/src/main.c index 465e457f70..b34810252e 100644 --- a/examples/host/cdc_msc_hid/src/main.c +++ b/examples/host/cdc_msc_hid/src/main.c @@ -61,24 +61,6 @@ int main(void) return 0; } -//--------------------------------------------------------------------+ -// USB CDC -//--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION static char serial_in_buffer[64] = { 0 }; - -// invoked ISR context -void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes) -{ - (void) event; - (void) pipe_id; - (void) xferred_bytes; - - printf(serial_in_buffer); - tu_memclr(serial_in_buffer, sizeof(serial_in_buffer)); - - tuh_cdc_receive(dev_addr, serial_in_buffer, sizeof(serial_in_buffer), true); // waiting for next data -} - //--------------------------------------------------------------------+ // TinyUSB Callbacks //--------------------------------------------------------------------+ diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 482ccf4beb..bdfbe3e744 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -36,52 +36,157 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -#if 0 typedef struct { tu_fifo_t ff; + + // mutex: read if ep rx, write if e tx OSAL_MUTEX_DEF(ff_mutex); + + // TODO xfer_fifo can skip this buffer + uint8_t* ep_buf; + uint16_t ep_bufsize; + uint8_t ep_addr; }tu_edpt_stream_t; -uint32_t tud_cdc_read_available (void); -uint32_t tud_cdc_read (void *buffer, uint32_t bufsize); -void tud_cdc_read_flush (void); -bool tud_cdc_peek (uint8_t *ui8); +bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool use_wr_mutex, bool overwritable, + void* ff_buf, uint16_t ff_bufsize, + uint8_t* ep_buf, uint16_t ep_bufsize) +{ + osal_mutex_t new_mutex = osal_mutex_create(&s->ff_mutex); + (void) new_mutex; -uint32_t tud_cdc_write (void const *buffer, uint32_t bufsize); -uint32_t tud_cdc_write_flush (void); -uint32_t tud_cdc_write_available (void); + tu_fifo_config(&s->ff, ff_buf, ff_bufsize, 1, overwritable); + tu_fifo_config_mutex(&s->ff, use_wr_mutex ? new_mutex : NULL, use_wr_mutex ? NULL : new_mutex); -//-------------------------------------------------------- -tu_edpt_stream_write() -#endif + s->ep_buf = ep_buf; + s->ep_bufsize = ep_bufsize; + + return true; +} + +bool tu_edpt_stream_clear(tu_edpt_stream_t* s) +{ + return tu_fifo_clear(&s->ff); +} + +uint32_t tud_edpt_stream_write_flush(uint8_t dev_addr, tu_edpt_stream_t* s) +{ + // No data to send + if ( !tu_fifo_count(&s->ff) ) return 0; + + // Claim the endpoint + // uint8_t const rhport = 0; + // TU_VERIFY( usbd_edpt_claim(rhport, p_cdc->ep_in), 0 ); + TU_VERIFY( usbh_edpt_claim(dev_addr, s->ep_addr) ); + + // Pull data from FIFO -> EP buf + uint16_t const count = tu_fifo_read_n(&s->ff, s->ep_buf, s->ep_bufsize); + + if ( count ) + { + //TU_ASSERT( usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 ); + TU_ASSERT( usbh_edpt_xfer(dev_addr, s->ep_addr, s->ep_buf, 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(rhport, p_cdc->ep_in); + + usbh_edpt_release(dev_addr, s->ep_addr); + return 0; + } +} + +uint32_t tu_edpt_stream_write(uint8_t daddr, tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize) +{ + uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); + + // flush if queue more than packet size + uint16_t const bulk_packet_size = (tuh_speed_get(daddr) == TUSB_SPEED_HIGH) ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; + if ( (tu_fifo_count(&s->ff) >= bulk_packet_size) + /* || ((CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE) && tu_fifo_full(&p_cdc->tx_ff)) */ ) + { + tud_edpt_stream_write_flush(daddr, s); + } + + return ret; +} + +void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) +{ + tu_fifo_write_n(&s->ff, s->ep_buf, (uint16_t) xferred_bytes); +} + +uint32_t tu_edpt_stream_read_xfer(uint8_t daddr, tu_edpt_stream_t* s) +{ + uint16_t available = tu_fifo_remaining(&s->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 + uint16_t const bulk_packet_size = (tuh_speed_get(daddr) == TUSB_SPEED_HIGH) ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; + TU_VERIFY(available >= bulk_packet_size); + + // claim endpoint + TU_VERIFY(usbh_edpt_claim(daddr, s->ep_addr), 0); + + // fifo can be changed before endpoint is claimed + available = tu_fifo_remaining(&s->ff); + + if ( available >= bulk_packet_size ) + { + // multiple of packet size limit by ep bufsize + uint16_t count = (uint16_t) (available & (bulk_packet_size -1)); + count = tu_min16(count, s->ep_bufsize); + + TU_ASSERT( usbh_edpt_xfer(daddr, s->ep_addr, s->ep_buf, count), 0 ); + return count; + }else + { + // Release endpoint since we don't make any transfer + usbh_edpt_release(daddr, s->ep_addr); + return 0; + } +} + +uint32_t tu_edpt_stream_read(uint8_t daddr, tu_edpt_stream_t* s, void* buffer, uint32_t bufsize) +{ + uint32_t num_read = tu_fifo_read_n(&s->ff, buffer, (uint16_t) bufsize); + tu_edpt_stream_read_xfer(daddr, s); + return num_read; +} + +uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t* s) +{ + return (uint32_t) tu_fifo_count(&s->ff); +} typedef struct { uint8_t daddr; - uint8_t itf_num; - uint8_t itf_protocol; - - uint8_t ep_notif; - uint8_t ep_in; - uint8_t ep_out; + uint8_t bInterfaceNumber; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; cdc_acm_capability_t acm_capability; + uint8_t ep_notif; // Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) - // uint8_t line_state; + uint8_t line_state; - // FIFO - tu_fifo_t rx_ff; - tu_fifo_t tx_ff; + tuh_xfer_cb_t user_control_cb; - uint8_t rx_ff_buf[CFG_TUH_CDC_RX_BUFSIZE]; - uint8_t tx_ff_buf[CFG_TUH_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_TUH_CDC_TX_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t tx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; - // Endpoint Transfer buffer - CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUH_CDC_RX_EPSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUH_CDC_TX_EPSIZE]; + uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t rx_ep_buf[CFG_TUH_CDC_TX_EPSIZE]; + } stream; } cdch_interface_t; @@ -92,19 +197,33 @@ typedef struct { CFG_TUSB_MEM_SECTION static cdch_interface_t cdch_data[CFG_TUH_CDC]; -static inline cdch_interface_t* get_itf(uint8_t dev_addr) +static inline cdch_interface_t* get_itf(uint8_t idx) { - for(size_t i=0; idaddr != 0) ? p_cdc : NULL; +} + +static inline cdch_interface_t* get_itf_by_ep_addr(uint8_t daddr, uint8_t ep_addr) +{ + for(uint8_t i=0; idaddr == daddr) && + (ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr)) + { + return p_cdc; + } } return NULL; } + static cdch_interface_t* find_new_itf(void) { - for(size_t i=0; idaddr == daddr && p_cdc->bInterfaceNumber == itf_num) return i; + } + + return TUSB_INDEX_INVALID; +} + +bool tuh_cdc_itf_get_info(uint8_t idx, tuh_cdc_itf_info_t* info) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc && info); + + info->daddr = p_cdc->daddr; + info->bInterfaceNumber = p_cdc->bInterfaceNumber; + info->bInterfaceSubClass = p_cdc->bInterfaceSubClass; + info->bInterfaceProtocol = p_cdc->bInterfaceProtocol; + + return true; +} + +bool tuh_cdc_mounted(uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); return p_cdc != NULL; } -uint32_t tuh_cdc_write(uint8_t dev_addr, void const* buffer, uint32_t bufsize) +bool tuh_cdc_get_dtr(uint8_t idx) { - (void) dev_addr; - (void) buffer; - (void) bufsize; + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); - return 0; + return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR) ? true : false; } -bool tuh_cdc_serial_is_mounted(uint8_t dev_addr) +bool tuh_cdc_get_rts(uint8_t idx) { - // TODO consider all AT Command as serial candidate - return tuh_cdc_mounted(dev_addr) && - (cdch_data[dev_addr-1].itf_protocol <= CDC_COMM_PROTOCOL_ATCOMMAND_CDMA); + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS) ? true : false; } -bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify) +uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) { - (void) is_notify; - TU_VERIFY( tuh_cdc_mounted(dev_addr) ); - TU_VERIFY( p_data != NULL && length); + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return tu_edpt_stream_write(p_cdc->daddr, &p_cdc->stream.tx, buffer, bufsize); +} - uint8_t const ep_out = cdch_data[dev_addr-1].ep_out; - if ( usbh_edpt_busy(dev_addr, ep_out) ) return false; +uint32_t tuh_cdc_write_flush(uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); - return usbh_edpt_xfer(dev_addr, ep_out, (void*)(uintptr_t) p_data, (uint16_t) length); + return tud_edpt_stream_write_flush(p_cdc->daddr, &p_cdc->stream.tx); } -bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify) +uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) { - (void) is_notify; - TU_VERIFY( tuh_cdc_mounted(dev_addr) ); - TU_VERIFY( p_buffer != NULL && length ); + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); - uint8_t const ep_in = cdch_data[dev_addr-1].ep_in; - if ( usbh_edpt_busy(dev_addr, ep_in) ) return false; + return tu_edpt_stream_read(p_cdc->daddr, &p_cdc->stream.rx, buffer, bufsize); +} - return usbh_edpt_xfer(dev_addr, ep_in, p_buffer, (uint16_t) length); +uint32_t tuh_cdc_read_available(uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return tu_edpt_stream_read_available(&p_cdc->stream.rx); } -bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb) +//--------------------------------------------------------------------+ +// Control Endpoint API +//--------------------------------------------------------------------+ + +// internal control complete to update state such as line state, encoding +static void cdch_internal_control_complete(tuh_xfer_t* xfer) { - cdch_interface_t const * p_cdc = get_itf(dev_addr); + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t* p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); + + if (xfer->result == XFER_RESULT_SUCCESS) + { + switch(xfer->setup->bRequest) + { + case CDC_REQUEST_SET_CONTROL_LINE_STATE: + p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + break; + + default: break; + } + } + + xfer->complete_cb = p_cdc->user_control_cb; + xfer->complete_cb(xfer); +} + +bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->acm_capability.support_line_request); tusb_control_request_t const request = @@ -176,19 +356,20 @@ bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xf .direction = TUSB_DIR_OUT }, .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, - .wValue = tu_htole16((uint16_t) ((dtr ? 1u : 0u) | (rts ? 2u : 0u))), - .wIndex = tu_htole16(p_cdc->itf_num), + .wValue = tu_htole16(line_state), + .wIndex = tu_htole16(p_cdc->bInterfaceNumber), .wLength = 0 }; + p_cdc->user_control_cb = complete_cb; tuh_xfer_t xfer = { - .daddr = dev_addr, + .daddr = p_cdc->daddr, .ep_addr = 0, .setup = &request, .buffer = NULL, - .complete_cb = complete_cb, - .user_data = 0 + .complete_cb = cdch_internal_control_complete, + .user_data = user_data }; return tuh_control_xfer(&xfer); @@ -202,32 +383,79 @@ void cdch_init(void) { tu_memclr(cdch_data, sizeof(cdch_data)); -// for(size_t i=0; istream.tx, true, false, + p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, + p_cdc->stream.tx_ep_buf, CFG_TUH_CDC_TX_EPSIZE); + + tu_edpt_stream_init(&p_cdc->stream.rx, false, false, + p_cdc->stream.rx_ff_buf, CFG_TUH_CDC_RX_BUFSIZE, + p_cdc->stream.rx_ep_buf, CFG_TUH_CDC_RX_EPSIZE); + } } -void cdch_close(uint8_t dev_addr) +void cdch_close(uint8_t daddr) { - cdch_interface_t * p_cdc = get_itf(dev_addr); - TU_VERIFY(p_cdc, ); - - // Invoke application callback - if (tuh_cdc_umount_cb) + for(uint8_t idx=0; idxdaddr == daddr) + { + // Invoke application callback + if (tuh_cdc_umount_cb) tuh_cdc_umount_cb(idx); + + //tu_memclr(p_cdc, sizeof(cdch_interface_t)); + p_cdc->daddr = 0; + p_cdc->bInterfaceNumber = 0; + tu_edpt_stream_clear(&p_cdc->stream.tx); + tu_edpt_stream_clear(&p_cdc->stream.rx); + } } - - tu_memclr(p_cdc, sizeof(cdch_interface_t)); } -bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) { - (void) ep_addr; - tuh_cdc_xfer_isr( dev_addr, event, 0, xferred_bytes ); + // TODO handle stall response, retry failed transfer ... + TU_ASSERT(event == XFER_RESULT_SUCCESS); + + cdch_interface_t * p_cdc = get_itf_by_ep_addr(daddr, ep_addr); + TU_ASSERT(p_cdc); + + if ( ep_addr == p_cdc->stream.tx.ep_addr ) + { + if ( 0 == tud_edpt_stream_write_flush(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 + uint16_t const bulk_packet_size = (tuh_speed_get(daddr) == TUSB_SPEED_HIGH) ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; + if ( !tu_fifo_count(&p_cdc->stream.tx.ff) && xferred_bytes && (0 == (xferred_bytes & (bulk_packet_size-1))) ) + { + if ( usbh_edpt_claim(daddr, p_cdc->stream.tx.ep_addr) ) + { + usbh_edpt_xfer(daddr, p_cdc->stream.tx.ep_addr, NULL, 0); + } + } + } + } + else if ( ep_addr == p_cdc->stream.rx.ep_addr ) + { + tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); + + // invoke receive callback + + // prepare for next transfer if needed + tu_edpt_stream_read_xfer(daddr, &p_cdc->stream.rx); + }else if ( ep_addr == p_cdc->ep_notif ) + { + // TODO handle notification endpoint + }else + { + TU_ASSERT(false); + } + return true; } @@ -238,7 +466,6 @@ bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32 bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { (void) rhport; - (void) max_len; // Only support ACM subclass // Protocol 0xFF can be RNDIS device for windows XP @@ -246,19 +473,22 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass && 0xFF != itf_desc->bInterfaceProtocol); + uint8_t const * p_desc_end = ((uint8_t const*) itf_desc) + max_len; + cdch_interface_t * p_cdc = find_new_itf(); TU_VERIFY(p_cdc); - p_cdc->daddr = dev_addr; - p_cdc->itf_num = itf_desc->bInterfaceNumber; - p_cdc->itf_protocol = itf_desc->bInterfaceProtocol; + p_cdc->daddr = dev_addr; + p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber; + p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; + p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol; + p_cdc->line_state = 0; //------------- Control Interface -------------// - uint16_t drv_len = tu_desc_len(itf_desc); uint8_t const * p_desc = tu_desc_next(itf_desc); // Communication Functional Descriptors - while( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) + while( (p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc)) ) { if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) ) { @@ -266,7 +496,6 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities; } - drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); } @@ -279,7 +508,6 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) ); p_cdc->ep_notif = desc_ep->bEndpointAddress; - drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); } @@ -288,42 +516,72 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) { // next to endpoint descriptor - drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); // data endpoints expected to be in pairs for(uint32_t i=0; i<2; i++) { tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; - TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); + TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && + TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) { - p_cdc->ep_in = desc_ep->bEndpointAddress; + p_cdc->stream.rx.ep_addr = desc_ep->bEndpointAddress; }else { - p_cdc->ep_out = desc_ep->bEndpointAddress; + p_cdc->stream.tx.ep_addr = desc_ep->bEndpointAddress; } - drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next( p_desc ); + p_desc = tu_desc_next(p_desc); } } return true; } -bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num) +static void config_cdc_complete(uint8_t daddr, uint8_t itf_num) { - if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(dev_addr); + uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); + + if (idx != TUSB_INDEX_INVALID) + { + if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); + + // Prepare for incoming data + cdch_interface_t* p_cdc = get_itf(idx); + tu_edpt_stream_read_xfer(daddr, &p_cdc->stream.rx); + } // notify usbh that driver enumeration is complete // itf_num+1 to account for data interface as well - usbh_driver_set_config_complete(dev_addr, itf_num+1); + usbh_driver_set_config_complete(daddr, itf_num+1); +} + +#if CFG_TUH_CDC_SET_DTRRTS_ON_ENUM +static void config_set_dtr_rts_complete (tuh_xfer_t* xfer) +{ + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + config_cdc_complete(xfer->daddr, itf_num); +} + +bool cdch_set_config(uint8_t daddr, uint8_t itf_num) +{ + uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); + return tuh_cdc_set_control_line_state(idx, CFG_TUH_CDC_SET_DTRRTS_ON_ENUM, config_set_dtr_rts_complete, 0); +} + +#else + +bool cdch_set_config(uint8_t daddr, uint8_t itf_num) +{ + config_cdc_complete(daddr, itf_num); return true; } #endif + +#endif diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index b2e75902d4..54e082e7d7 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -37,6 +37,11 @@ // Class Driver Configuration //--------------------------------------------------------------------+ +// Set DTR ( bit 0), RTS (bit 1) on enumeration/mounted +#ifndef CFG_TUH_CDC_SET_DTRRTS_ON_ENUM +#define CFG_TUH_CDC_SET_DTRRTS_ON_ENUM 0 +#endif + // RX FIFO size #ifndef CFG_TUH_CDC_RX_BUFSIZE #define CFG_TUH_CDC_RX_BUFSIZE USBH_EPSIZE_BULK_MAX @@ -61,43 +66,76 @@ // Application API //--------------------------------------------------------------------+ -bool tuh_cdc_mounted(uint8_t dev_addr); +typedef struct +{ + uint8_t daddr; + uint8_t bInterfaceNumber; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; +} tuh_cdc_itf_info_t; + +// Get Interface index from device address + interface number +// return TUSB_INDEX_INVALID (0xFF) if not found +uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num); + +// Get Interface information +// return true if index is correct and interface is currently mounted +bool tuh_cdc_itf_get_info(uint8_t idx, tuh_cdc_itf_info_t* info); + +// Check if a interface is mounted +bool tuh_cdc_mounted(uint8_t idx); + +// Get current DTR status +bool tuh_cdc_get_dtr(uint8_t idx); + +// Get current RTS status +bool tuh_cdc_get_rts(uint8_t idx); + +// Check if interface is connected (DTR active) +TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) +{ + return tuh_cdc_get_dtr(idx); +} + +// Write to cdc interface +uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize); + +// Force sending data if possible, return number of forced bytes +uint32_t tuh_cdc_write_flush(uint8_t idx); + +// Read from cdc interface +uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize); -uint32_t tuh_cdc_write(uint8_t dev_addr, void const* buffer, uint32_t bufsize); -//uint32_t tuh_cdc_read(uint8_t dev_addr, void* buffer, uint32_t bufsize); +// Get the number of bytes available for reading +uint32_t tuh_cdc_read_available(uint8_t idx); //--------------------------------------------------------------------+ // Control Endpoint (Request) API //--------------------------------------------------------------------+ -// Set Control Line State (DTR, RTS) -bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb); +// Send control request to Set Control Line State: DTR (bit 0), RTS (bit 1) +bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb) +// Connect by set both DTR, RTS +static inline bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return tuh_cdc_set_control_line_state(dev_addr, true, true, complete_cb); + return tuh_cdc_set_control_line_state(idx, CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS, complete_cb, user_data); } -static inline bool tuh_cdc_disconnect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb) +// Disconnect by clear both DTR, RTS +static inline bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return tuh_cdc_set_control_line_state(dev_addr, false, false, complete_cb); + return tuh_cdc_set_control_line_state(idx, 0x00, complete_cb, user_data); } //------------- Application Callback -------------// // Invoked when a device with CDC interface is mounted -TU_ATTR_WEAK void tuh_cdc_mount_cb(uint8_t dev_addr); +// idx is index of cdc interface in the internal pool. +TU_ATTR_WEAK void tuh_cdc_mount_cb(uint8_t idx); // Invoked when a device with CDC interface is unmounted -TU_ATTR_WEAK void tuh_cdc_umount_cb(uint8_t dev_addr); - - -/** \brief Check if device support CDC Serial interface or not - * \param[in] dev_addr device address - * \retval true if device supports - * \retval false if device does not support or is not mounted - */ -bool tuh_cdc_serial_is_mounted(uint8_t dev_addr); +TU_ATTR_WEAK void tuh_cdc_umount_cb(uint8_t idx); /** \brief Check if the interface is currently busy or not * \param[in] dev_addr device address @@ -108,7 +146,7 @@ bool tuh_cdc_serial_is_mounted(uint8_t dev_addr); * can be scheduled. User needs to make sure the corresponding interface is mounted * (by \ref tuh_cdc_serial_is_mounted) before calling this function. */ -bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid); +// bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid); /** \brief Perform USB OUT transfer to device * \param[in] dev_addr device address @@ -121,7 +159,7 @@ bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid); * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION. */ -bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify); +// bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify); /** \brief Perform USB IN transfer to get data from device * \param[in] dev_addr device address @@ -134,7 +172,7 @@ bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool i * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION. */ -bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify); +// bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify); //--------------------------------------------------------------------+ // CDC APPLICATION CALLBACKS @@ -151,7 +189,7 @@ bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is * - XFER_RESULT_STALLED : previously scheduled transfer is stalled by device. * \note */ -void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes); +// void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes); /// @} // group CDC_Serial_Host /// @} From 37529c41da3884c235ac4f582b7202331877142c Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 10:46:47 +0700 Subject: [PATCH 09/28] fix ci --- src/class/cdc/cdc_host.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index bdfbe3e744..5aec41cbc7 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -54,6 +54,7 @@ bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool use_wr_mutex, bool overwritab { osal_mutex_t new_mutex = osal_mutex_create(&s->ff_mutex); (void) new_mutex; + (void) use_wr_mutex; tu_fifo_config(&s->ff, ff_buf, ff_bufsize, 1, overwritable); tu_fifo_config_mutex(&s->ff, use_wr_mutex ? new_mutex : NULL, use_wr_mutex ? NULL : new_mutex); From d1ea3844f70a5add6e073aa8fa6b562413db4929 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 11:04:57 +0700 Subject: [PATCH 10/28] rename TU_LOG_VAR to TU_LOG_PTR, print out setup of failed control transfer when LOG=1 --- src/common/tusb_debug.h | 18 +++++++++--------- src/host/usbh.c | 8 ++++++-- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/common/tusb_debug.h b/src/common/tusb_debug.h index ac5bee6ece..65fd1920dd 100644 --- a/src/common/tusb_debug.h +++ b/src/common/tusb_debug.h @@ -66,7 +66,7 @@ static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) #define TU_LOG(n, ...) TU_XSTRCAT(TU_LOG, n)(__VA_ARGS__) #define TU_LOG_MEM(n, ...) TU_XSTRCAT3(TU_LOG, n, _MEM)(__VA_ARGS__) #define TU_LOG_ARR(n, ...) TU_XSTRCAT3(TU_LOG, n, _ARR)(__VA_ARGS__) -#define TU_LOG_VAR(n, ...) TU_XSTRCAT3(TU_LOG, n, _VAR)(__VA_ARGS__) +#define TU_LOG_PTR(n, ...) TU_XSTRCAT3(TU_LOG, n, _PTR)(__VA_ARGS__) #define TU_LOG_INT(n, ...) TU_XSTRCAT3(TU_LOG, n, _INT)(__VA_ARGS__) #define TU_LOG_HEX(n, ...) TU_XSTRCAT3(TU_LOG, n, _HEX)(__VA_ARGS__) #define TU_LOG_LOCATION() tu_printf("%s: %d:\r\n", __PRETTY_FUNCTION__, __LINE__) @@ -76,7 +76,7 @@ static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) #define TU_LOG1 tu_printf #define TU_LOG1_MEM tu_print_mem #define TU_LOG1_ARR(_x, _n) tu_print_arr((uint8_t const*)(_x), _n) -#define TU_LOG1_VAR(_x) tu_print_arr((uint8_t const*)(_x), sizeof(*(_x))) +#define TU_LOG1_PTR(_x) tu_print_arr((uint8_t const*)(_x), sizeof(*(_x))) #define TU_LOG1_INT(_x) tu_printf(#_x " = %ld\r\n", (unsigned long) (_x) ) #define TU_LOG1_HEX(_x) tu_printf(#_x " = %lX\r\n", (unsigned long) (_x) ) @@ -85,7 +85,7 @@ static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) #define TU_LOG2 TU_LOG1 #define TU_LOG2_MEM TU_LOG1_MEM #define TU_LOG2_ARR TU_LOG1_ARR - #define TU_LOG2_VAR TU_LOG1_VAR + #define TU_LOG2_PTR TU_LOG1_PTR #define TU_LOG2_INT TU_LOG1_INT #define TU_LOG2_HEX TU_LOG1_HEX #endif @@ -95,7 +95,7 @@ static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize) #define TU_LOG3 TU_LOG1 #define TU_LOG3_MEM TU_LOG1_MEM #define TU_LOG3_ARR TU_LOG1_ARR - #define TU_LOG3_VAR TU_LOG1_VAR + #define TU_LOG3_PTR TU_LOG1_PTR #define TU_LOG3_INT TU_LOG1_INT #define TU_LOG3_HEX TU_LOG1_HEX #endif @@ -132,7 +132,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG #define TU_LOG(n, ...) #define TU_LOG_MEM(n, ...) - #define TU_LOG_VAR(n, ...) + #define TU_LOG_PTR(n, ...) #define TU_LOG_INT(n, ...) #define TU_LOG_HEX(n, ...) #define TU_LOG_LOCATION() @@ -143,14 +143,14 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #define TU_LOG0(...) #define TU_LOG0_MEM(...) -#define TU_LOG0_VAR(...) +#define TU_LOG0_PTR(...) #define TU_LOG0_INT(...) #define TU_LOG0_HEX(...) #ifndef TU_LOG1 #define TU_LOG1(...) #define TU_LOG1_MEM(...) - #define TU_LOG1_VAR(...) + #define TU_LOG1_PTR(...) #define TU_LOG1_INT(...) #define TU_LOG1_HEX(...) #endif @@ -158,7 +158,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG2 #define TU_LOG2(...) #define TU_LOG2_MEM(...) - #define TU_LOG2_VAR(...) + #define TU_LOG2_PTR(...) #define TU_LOG2_INT(...) #define TU_LOG2_HEX(...) #endif @@ -166,7 +166,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 #ifndef TU_LOG3 #define TU_LOG3(...) #define TU_LOG3_MEM(...) - #define TU_LOG3_VAR(...) + #define TU_LOG3_PTR(...) #define TU_LOG3_INT(...) #define TU_LOG3_HEX(...) #endif diff --git a/src/host/usbh.c b/src/host/usbh.c index 4b278f2da0..59b1c32800 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -540,7 +540,7 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) const uint8_t rhport = usbh_get_rhport(daddr); TU_LOG2("[%u:%u] %s: ", rhport, daddr, xfer->setup->bRequest <= TUSB_REQ_SYNCH_FRAME ? tu_str_std_request[xfer->setup->bRequest] : "Unknown Request"); - TU_LOG2_VAR(xfer->setup); + TU_LOG2_PTR(xfer->setup); TU_LOG2("\r\n"); if (xfer->complete_cb) @@ -618,7 +618,11 @@ static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result if (XFER_RESULT_SUCCESS != result) { - TU_LOG1("[%u:%u] Control %s\r\n", rhport, dev_addr, result == XFER_RESULT_STALLED ? "STALLED" : "FAILED"); + TU_LOG1("[%u:%u] Control %s, xferred_bytes = %lu\r\n", rhport, dev_addr, result == XFER_RESULT_STALLED ? "STALLED" : "FAILED", xferred_bytes); + #if CFG_TUSB_DEBUG == 1 + TU_LOG1_PTR(request); + TU_LOG1("\r\n"); + #endif // terminate transfer if any stage failed _xfer_complete(dev_addr, result); From cb2af4c0bc096e57c3486945eda43dbc26b3829a Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 11:46:58 +0700 Subject: [PATCH 11/28] minor debug log --- src/class/cdc/cdc_host.c | 8 ++++ src/class/msc/msc_host.c | 13 ++++-- src/host/usbh.c | 85 ++++++++++++++++++++++------------------ 3 files changed, 63 insertions(+), 43 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 5aec41cbc7..83c6238844 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -33,6 +33,12 @@ #include "cdc_host.h" + +// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message +#define CDCH_DEBUG 2 + +#define TU_LOG_CDCH(...) TU_LOG(CDCH_DEBUG, __VA_ARGS__) + //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ @@ -348,6 +354,8 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->acm_capability.support_line_request); + TU_LOG_CDCH("CDC Set Control Line State\r\n"); + tusb_control_request_t const request = { .bmRequestType_bit = diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index 32f75a84b8..6724e486c4 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -33,6 +33,11 @@ #include "msc_host.h" +// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message +#define MSCH_DEBUG 2 + +#define TU_LOG_MSCH(...) TU_LOG(MSCH_DEBUG, __VA_ARGS__) + //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ @@ -417,7 +422,7 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) p_msc->configured = true; //------------- Get Max Lun -------------// - TU_LOG2("MSC Get Max Lun\r\n"); + TU_LOG_MSCH("MSC Get Max Lun\r\n"); tusb_control_request_t const request = { .bmRequestType_bit = @@ -456,7 +461,7 @@ static void config_get_maxlun_complete (tuh_xfer_t* xfer) p_msc->max_lun++; // MAX LUN is minus 1 by specs // TODO multiple LUN support - TU_LOG2("SCSI Test Unit Ready\r\n"); + TU_LOG_MSCH("SCSI Test Unit Ready\r\n"); uint8_t const lun = 0; tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete, 0); } @@ -469,14 +474,14 @@ static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_d if (csw->status == 0) { // Unit is ready, read its capacity - TU_LOG2("SCSI Read Capacity\r\n"); + TU_LOG_MSCH("SCSI Read Capacity\r\n"); tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete, 0); }else { // Note: During enumeration, some device fails Test Unit Ready and require a few retries // with Request Sense to start working !! // TODO limit number of retries - TU_LOG2("SCSI Request Sense\r\n"); + TU_LOG_MSCH("SCSI Request Sense\r\n"); TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, _msch_buffer, config_request_sense_complete, 0)); } diff --git a/src/host/usbh.c b/src/host/usbh.c index 59b1c32800..36fc5fded8 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -46,8 +46,10 @@ #define CFG_TUH_INTERFACE_MAX 8 #endif -// Debug level of USBD -#define USBH_DBG_LVL 2 +// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message +#define USBH_DEBUG 2 + +#define TU_LOG_USBH(...) TU_LOG(USBH_DEBUG, __VA_ARGS__) //--------------------------------------------------------------------+ // USBH-HCD common data structure @@ -324,11 +326,11 @@ bool tuh_init(uint8_t controller_id) // skip if already initialized if ( tuh_inited() ) return true; - TU_LOG2("USBH init on controller %u\r\n", controller_id); - TU_LOG2_INT(sizeof(usbh_device_t)); - TU_LOG2_INT(sizeof(hcd_event_t)); - TU_LOG2_INT(sizeof(_ctrl_xfer)); - TU_LOG2_INT(sizeof(tuh_xfer_t)); + TU_LOG_USBH("USBH init on controller %u\r\n", controller_id); + TU_LOG_INT(USBH_DEBUG, sizeof(usbh_device_t)); + TU_LOG_INT(USBH_DEBUG, sizeof(hcd_event_t)); + TU_LOG_INT(USBH_DEBUG, sizeof(_ctrl_xfer)); + TU_LOG_INT(USBH_DEBUG, sizeof(tuh_xfer_t)); // Event queue _usbh_q = osal_queue_create( &_usbh_qdef ); @@ -353,7 +355,7 @@ bool tuh_init(uint8_t controller_id) // Class drivers for (uint8_t drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++) { - TU_LOG2("%s init\r\n", usbh_class_drivers[drv_id].name); + TU_LOG_USBH("%s init\r\n", usbh_class_drivers[drv_id].name); usbh_class_drivers[drv_id].init(); } @@ -401,12 +403,12 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) case HCD_EVENT_DEVICE_ATTACH: // TODO due to the shared _usbh_ctrl_buf, we must complete enumerating // one device before enumerating another one. - TU_LOG2("[%u:] USBH DEVICE ATTACH\r\n", event.rhport); + TU_LOG_USBH("[%u:] USBH DEVICE ATTACH\r\n", event.rhport); enum_new_device(&event); break; case HCD_EVENT_DEVICE_REMOVE: - TU_LOG2("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port); + TU_LOG_USBH("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port); process_device_unplugged(event.rhport, event.connection.hub_addr, event.connection.hub_port); #if CFG_TUH_HUB @@ -425,7 +427,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const ep_dir = tu_edpt_dir(ep_addr); - TU_LOG2("on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len); + TU_LOG_USBH("on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len); if (event.dev_addr == 0) { @@ -449,7 +451,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) uint8_t drv_id = dev->ep2drv[epnum][ep_dir]; if(drv_id < USBH_CLASS_DRIVER_COUNT) { - TU_LOG2("%s xfer callback\r\n", usbh_class_drivers[drv_id].name); + TU_LOG_USBH("%s xfer callback\r\n", usbh_class_drivers[drv_id].name); usbh_class_drivers[drv_id].xfer_cb(event.dev_addr, ep_addr, event.xfer_complete.result, event.xfer_complete.len); } else @@ -539,9 +541,11 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) TU_VERIFY(is_idle); const uint8_t rhport = usbh_get_rhport(daddr); - TU_LOG2("[%u:%u] %s: ", rhport, daddr, xfer->setup->bRequest <= TUSB_REQ_SYNCH_FRAME ? tu_str_std_request[xfer->setup->bRequest] : "Unknown Request"); - TU_LOG2_PTR(xfer->setup); - TU_LOG2("\r\n"); + TU_LOG_USBH("[%u:%u] %s: ", rhport, daddr, + (xfer->setup->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && xfer->setup->bRequest <= TUSB_REQ_SYNCH_FRAME) ? + tu_str_std_request[xfer->setup->bRequest] : "Class Request"); + TU_LOG_PTR(USBH_DEBUG, xfer->setup); + TU_LOG_USBH("\r\n"); if (xfer->complete_cb) { @@ -585,7 +589,7 @@ TU_ATTR_ALWAYS_INLINE static inline void _set_control_xfer_stage(uint8_t stage) static void _xfer_complete(uint8_t daddr, xfer_result_t result) { - TU_LOG2("\r\n"); + TU_LOG_USBH("\r\n"); // duplicate xfer since user can execute control transfer within callback tusb_control_request_t const request = _ctrl_xfer.request; @@ -643,8 +647,8 @@ static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result case CONTROL_STAGE_DATA: if (request->wLength) { - TU_LOG2("[%u:%u] Control data:\r\n", rhport, dev_addr); - TU_LOG2_MEM(_ctrl_xfer.buffer, xferred_bytes, 2); + TU_LOG_USBH("[%u:%u] Control data:\r\n", rhport, dev_addr); + TU_LOG_MEM(USBH_DEBUG, _ctrl_xfer.buffer, xferred_bytes, 2); } _ctrl_xfer.actual_len = (uint16_t) xferred_bytes; @@ -760,7 +764,7 @@ bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * b uint8_t const dir = tu_edpt_dir(ep_addr); tu_edpt_state_t* ep_state = &dev->ep_status[epnum][dir]; - TU_LOG2(" Queue EP %02X with %u bytes ... ", ep_addr, total_bytes); + TU_LOG_USBH(" Queue EP %02X with %u bytes ... ", ep_addr, total_bytes); // Attempt to transfer on a busy endpoint, sound like an race condition ! TU_ASSERT(ep_state->busy == 0); @@ -776,7 +780,7 @@ bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * b if ( hcd_edpt_xfer(dev->rhport, dev_addr, ep_addr, buffer, total_bytes) ) { - TU_LOG2("OK\r\n"); + TU_LOG_USBH("OK\r\n"); return true; }else { @@ -791,7 +795,7 @@ bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * b static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size) { - TU_LOG2("[%u:%u] Open EP0 with Size = %u\r\n", usbh_get_rhport(dev_addr), dev_addr, max_packet_size); + TU_LOG_USBH("[%u:%u] Open EP0 with Size = %u\r\n", usbh_get_rhport(dev_addr), dev_addr, max_packet_size); tusb_desc_endpoint_t ep0_desc = { @@ -960,7 +964,7 @@ bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void* bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG2("HID Get Report Descriptor\r\n"); + TU_LOG_USBH("HID Get Report Descriptor\r\n"); tusb_control_request_t const request = { .bmRequestType_bit = @@ -999,7 +1003,7 @@ bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_ bool tuh_configuration_set(uint8_t daddr, uint8_t config_num, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG2("Set Configuration = %d\r\n", config_num); + TU_LOG_USBH("Set Configuration = %d\r\n", config_num); tusb_control_request_t const request = { @@ -1103,11 +1107,11 @@ static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t h (hub_port == 0 || dev->hub_port == hub_port) && // hub_port = 0 means all devices of downstream hub dev->connected) { - TU_LOG2(" Address = %u\r\n", dev_addr); + TU_LOG_USBH(" Address = %u\r\n", dev_addr); if (is_hub_addr(dev_addr)) { - TU_LOG(USBH_DBG_LVL, "HUB address = %u is unmounted\r\n", dev_addr); + TU_LOG(USBH_DEBUG, "HUB address = %u is unmounted\r\n", dev_addr); // If the device itself is a usb hub, unplug downstream devices. // FIXME un-roll recursive calls to prevent potential stack overflow process_device_unplugged(rhport, dev_addr, 0); @@ -1120,7 +1124,7 @@ static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t h // Close class driver for (uint8_t drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++) { - TU_LOG2("%s close\r\n", usbh_class_drivers[drv_id].name); + TU_LOG_USBH("%s close\r\n", usbh_class_drivers[drv_id].name); usbh_class_drivers[drv_id].close(dev_addr); } @@ -1245,7 +1249,7 @@ static void process_enumeration(tuh_xfer_t* xfer) TU_ASSERT( usbh_edpt_control_open(addr0, 8), ); // Get first 8 bytes of device descriptor for Control Endpoint size - TU_LOG2("Get 8 byte of Device Descriptor\r\n"); + TU_LOG_USBH("Get 8 byte of Device Descriptor\r\n"); TU_ASSERT(tuh_descriptor_get_device(addr0, _usbh_ctrl_buf, 8, process_enumeration, ENUM_SET_ADDR), ); } break; @@ -1254,7 +1258,7 @@ static void process_enumeration(tuh_xfer_t* xfer) case ENUM_RESET_2: // TODO not used by now, but may be needed for some devices !? // Reset device again before Set Address - TU_LOG2("Port reset2 \r\n"); + TU_LOG_USBH("Port reset2 \r\n"); if (_dev0.hub_addr == 0) { // connected directly to roothub @@ -1294,7 +1298,7 @@ static void process_enumeration(tuh_xfer_t* xfer) TU_ASSERT( usbh_edpt_control_open(new_addr, new_dev->ep0_size), ); // Get full device descriptor - TU_LOG2("Get Device Descriptor\r\n"); + TU_LOG_USBH("Get Device Descriptor\r\n"); TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_ctrl_buf, sizeof(tusb_desc_device_t), process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC), ); } break; @@ -1315,7 +1319,7 @@ static void process_enumeration(tuh_xfer_t* xfer) // Get 9-byte for total length uint8_t const config_idx = CONFIG_NUM - 1; - TU_LOG2("Get Configuration[0] Descriptor (9 bytes)\r\n"); + TU_LOG_USBH("Get Configuration[0] Descriptor (9 bytes)\r\n"); TU_ASSERT( tuh_descriptor_get_configuration(daddr, config_idx, _usbh_ctrl_buf, 9, process_enumeration, ENUM_GET_FULL_CONFIG_DESC), ); } break; @@ -1332,7 +1336,7 @@ static void process_enumeration(tuh_xfer_t* xfer) // Get full configuration descriptor uint8_t const config_idx = CONFIG_NUM - 1; - TU_LOG2("Get Configuration[0] Descriptor\r\n"); + TU_LOG_USBH("Get Configuration[0] Descriptor\r\n"); TU_ASSERT( tuh_descriptor_get_configuration(daddr, config_idx, _usbh_ctrl_buf, total_len, process_enumeration, ENUM_SET_CONFIG), ); } break; @@ -1347,7 +1351,7 @@ static void process_enumeration(tuh_xfer_t* xfer) case ENUM_CONFIG_DRIVER: { - TU_LOG2("Device configured\r\n"); + TU_LOG_USBH("Device configured\r\n"); usbh_device_t* dev = get_device(daddr); TU_ASSERT(dev, ); @@ -1387,7 +1391,7 @@ static bool enum_new_device(hcd_event_t* event) if ( !hcd_port_connect_status(_dev0.rhport) ) return true; _dev0.speed = hcd_port_speed_get(_dev0.rhport ); - TU_LOG2("%s Speed\r\n", tu_str_speed[_dev0.speed]); + TU_LOG_USBH("%s Speed\r\n", tu_str_speed[_dev0.speed]); // fake transfer to kick-off the enumeration process tuh_xfer_t xfer; @@ -1444,7 +1448,7 @@ static bool enum_request_set_addr(void) uint8_t const new_addr = get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB); TU_ASSERT(new_addr != 0); - TU_LOG2("Set Address = %d\r\n", new_addr); + TU_LOG_USBH("Set Address = %d\r\n", new_addr); usbh_device_t* new_dev = get_device(new_addr); @@ -1488,9 +1492,12 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur { usbh_device_t* dev = get_device(dev_addr); - uint8_t const* desc_end = ((uint8_t const*) desc_cfg) + tu_le16toh(desc_cfg->wTotalLength); + uint16_t const total_len = tu_le16toh(desc_cfg->wTotalLength); + uint8_t const* desc_end = ((uint8_t const*) desc_cfg) + total_len; uint8_t const* p_desc = tu_desc_next(desc_cfg); + TU_LOG_USBH("Parsing Configuration descriptor (wTotalLength = %u)\r\n", total_len); + // parse each interfaces while( p_desc < desc_end ) { @@ -1535,7 +1542,7 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur if ( driver->open(dev->rhport, dev_addr, desc_itf, drv_len) ) { // open successfully - TU_LOG2(" %s opened\r\n", driver->name); + TU_LOG_USBH(" %s opened\r\n", driver->name); // bind (associated) interfaces to found driver for(uint8_t i=0; i= USBH_CLASS_DRIVER_COUNT ) { - TU_LOG(USBH_DBG_LVL, "Interface %u: class = %u subclass = %u protocol = %u is not supported\r\n", + TU_LOG(USBH_DEBUG, "Interface %u: class = %u subclass = %u protocol = %u is not supported\r\n", desc_itf->bInterfaceNumber, desc_itf->bInterfaceClass, desc_itf->bInterfaceSubClass, desc_itf->bInterfaceProtocol); } } @@ -1580,7 +1587,7 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) if (drv_id != DRVID_INVALID) { usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id]; - TU_LOG2("%s set config: itf = %u\r\n", driver->name, itf_num); + TU_LOG_USBH("%s set config: itf = %u\r\n", driver->name, itf_num); driver->set_config(dev_addr, itf_num); break; } @@ -1593,7 +1600,7 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) if (is_hub_addr(dev_addr)) { - TU_LOG(USBH_DBG_LVL, "HUB address = %u is mounted\r\n", dev_addr); + TU_LOG(USBH_DEBUG, "HUB address = %u is mounted\r\n", dev_addr); }else { // Invoke callback if available From b3e63c335af9345e505575e5bc8ba0281ac73692 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 11:47:07 +0700 Subject: [PATCH 12/28] updat cdc host app --- examples/host/cdc_msc_hid/src/cdc_app.c | 55 ++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index 29da02abc5..123cb33f0b 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -25,6 +25,7 @@ */ #include "tusb.h" +#include "bsp/board.h" //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION @@ -33,19 +34,61 @@ //------------- IMPLEMENTATION -------------// +size_t get_console_inputs(uint8_t* buf, size_t bufsize) +{ + size_t count = 0; + while (count < bufsize) + { + int ch = board_getchar(); + if ( ch <= 0 ) break; + + buf[count] = (uint8_t) ch; + count++; + } + + return count; +} + void cdc_app_task(void) { + uint8_t buf[64+1]; // +1 for extra null character + memset(buf, 0, sizeof(buf)); + size_t count = get_console_inputs(buf, sizeof(buf)-1); + + // loop over all mounted interfaces + for(size_t idx=0; idx cdc interfaces + if (count) + { + tuh_cdc_write(idx, buf, count); + tuh_cdc_write_flush(idx); + } + + // cdc interfaces -> console + if ( tuh_cdc_read_available(idx) ) + { + printf((char*) buf); + } + } + } } -void tuh_cdc_mount_cb(uint8_t dev_addr) +void tuh_cdc_mount_cb(uint8_t idx) { - (void) dev_addr; - printf("A CDC device is mounted\r\n"); + tuh_cdc_itf_info_t itf_info; + tuh_cdc_itf_get_info(idx, &itf_info); + + printf("CDC Interface is mounted: device address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.bInterfaceNumber); } -void tuh_cdc_umount_cb(uint8_t dev_addr) +void tuh_cdc_umount_cb(uint8_t idx) { - (void) dev_addr; - printf("A CDC device is unmounted\r\n"); + tuh_cdc_itf_info_t itf_info; + tuh_cdc_itf_get_info(idx, &itf_info); + + printf("CDC Interface is unmounted: device address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.bInterfaceNumber); } From 76021c7359fd330f547a1c22c5c00a23aa5c2bf0 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 11:49:28 +0700 Subject: [PATCH 13/28] rename tud_edpt_stream_write_xfer --- src/class/cdc/cdc_host.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 83c6238844..79e29796c7 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -76,7 +76,7 @@ bool tu_edpt_stream_clear(tu_edpt_stream_t* s) return tu_fifo_clear(&s->ff); } -uint32_t tud_edpt_stream_write_flush(uint8_t dev_addr, tu_edpt_stream_t* s) +uint32_t tud_edpt_stream_write_xfer(uint8_t dev_addr, tu_edpt_stream_t* s) { // No data to send if ( !tu_fifo_count(&s->ff) ) return 0; @@ -114,7 +114,7 @@ uint32_t tu_edpt_stream_write(uint8_t daddr, tu_edpt_stream_t* s, void const *bu if ( (tu_fifo_count(&s->ff) >= bulk_packet_size) /* || ((CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE) && tu_fifo_full(&p_cdc->tx_ff)) */ ) { - tud_edpt_stream_write_flush(daddr, s); + tud_edpt_stream_write_xfer(daddr, s); } return ret; @@ -302,7 +302,7 @@ uint32_t tuh_cdc_write_flush(uint8_t idx) cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tud_edpt_stream_write_flush(p_cdc->daddr, &p_cdc->stream.tx); + return tud_edpt_stream_write_xfer(p_cdc->daddr, &p_cdc->stream.tx); } uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) @@ -435,7 +435,7 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t if ( ep_addr == p_cdc->stream.tx.ep_addr ) { - if ( 0 == tud_edpt_stream_write_flush(daddr, &p_cdc->stream.tx) ) + if ( 0 == tud_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 From 22b62f871263ae170965a037e4f677a8a8e49709 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 12:07:12 +0700 Subject: [PATCH 14/28] add tu_edpt_stream_write_zlp_if_needed() --- src/class/cdc/cdc_host.c | 44 ++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 79e29796c7..f8d996e174 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -76,15 +76,30 @@ bool tu_edpt_stream_clear(tu_edpt_stream_t* s) return tu_fifo_clear(&s->ff); } -uint32_t tud_edpt_stream_write_xfer(uint8_t dev_addr, tu_edpt_stream_t* s) +bool tu_edpt_stream_write_zlp_if_needed(uint8_t daddr, tu_edpt_stream_t* s, uint32_t last_xferred_bytes) { - // No data to send - if ( !tu_fifo_count(&s->ff) ) return 0; + uint16_t const bulk_packet_size = (tuh_speed_get(daddr) == TUSB_SPEED_HIGH) ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; + + // ZLP condition: no pending data, last transferred bytes is multiple of packet size + TU_VERIFY( !tu_fifo_count(&s->ff) && last_xferred_bytes && (0 == (last_xferred_bytes & (bulk_packet_size-1))) ); + + if ( usbh_edpt_claim(daddr, s->ep_addr) ) + { + TU_ASSERT( usbh_edpt_xfer(daddr, s->ep_addr, NULL, 0) ); + } + + return true; +} + +uint32_t tu_edpt_stream_write_xfer(uint8_t daddr, tu_edpt_stream_t* s) +{ + // skip if no data + TU_VERIFY( tu_fifo_count(&s->ff), 0 ); // Claim the endpoint // uint8_t const rhport = 0; // TU_VERIFY( usbd_edpt_claim(rhport, p_cdc->ep_in), 0 ); - TU_VERIFY( usbh_edpt_claim(dev_addr, s->ep_addr) ); + TU_VERIFY( usbh_edpt_claim(daddr, s->ep_addr) ); // Pull data from FIFO -> EP buf uint16_t const count = tu_fifo_read_n(&s->ff, s->ep_buf, s->ep_bufsize); @@ -92,7 +107,7 @@ uint32_t tud_edpt_stream_write_xfer(uint8_t dev_addr, tu_edpt_stream_t* s) if ( count ) { //TU_ASSERT( usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 ); - TU_ASSERT( usbh_edpt_xfer(dev_addr, s->ep_addr, s->ep_buf, count), 0 ); + TU_ASSERT( usbh_edpt_xfer(daddr, s->ep_addr, s->ep_buf, count), 0 ); return count; }else { @@ -100,7 +115,7 @@ uint32_t tud_edpt_stream_write_xfer(uint8_t dev_addr, tu_edpt_stream_t* s) // Note: data is dropped if terminal is not connected //usbd_edpt_release(rhport, p_cdc->ep_in); - usbh_edpt_release(dev_addr, s->ep_addr); + usbh_edpt_release(daddr, s->ep_addr); return 0; } } @@ -114,7 +129,7 @@ uint32_t tu_edpt_stream_write(uint8_t daddr, tu_edpt_stream_t* s, void const *bu if ( (tu_fifo_count(&s->ff) >= bulk_packet_size) /* || ((CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE) && tu_fifo_full(&p_cdc->tx_ff)) */ ) { - tud_edpt_stream_write_xfer(daddr, s); + tu_edpt_stream_write_xfer(daddr, s); } return ret; @@ -302,7 +317,7 @@ uint32_t tuh_cdc_write_flush(uint8_t idx) cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tud_edpt_stream_write_xfer(p_cdc->daddr, &p_cdc->stream.tx); + return tu_edpt_stream_write_xfer(p_cdc->daddr, &p_cdc->stream.tx); } uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) @@ -435,18 +450,11 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t if ( ep_addr == p_cdc->stream.tx.ep_addr ) { - if ( 0 == tud_edpt_stream_write_xfer(daddr, &p_cdc->stream.tx) ) + if ( 0 == tu_edpt_stream_write_xfer(daddr, &p_cdc->stream.tx) ) { - // If there is no data left, a ZLP should be sent if + // If there is no data left, a ZLP should be sent if needed // xferred_bytes is multiple of EP Packet size and not zero - uint16_t const bulk_packet_size = (tuh_speed_get(daddr) == TUSB_SPEED_HIGH) ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; - if ( !tu_fifo_count(&p_cdc->stream.tx.ff) && xferred_bytes && (0 == (xferred_bytes & (bulk_packet_size-1))) ) - { - if ( usbh_edpt_claim(daddr, p_cdc->stream.tx.ep_addr) ) - { - usbh_edpt_xfer(daddr, p_cdc->stream.tx.ep_addr, NULL, 0); - } - } + tu_edpt_stream_write_zlp_if_needed(daddr, &p_cdc->stream.tx, xferred_bytes); } } else if ( ep_addr == p_cdc->stream.rx.ep_addr ) From badb30a6c3d0748b52d7c9db5a48b7bef21b4c1a Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 12:25:13 +0700 Subject: [PATCH 15/28] correct cdc host app --- examples/host/cdc_msc_hid/src/cdc_app.c | 17 +++++++++++------ src/class/cdc/cdc_host.c | 3 ++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index 123cb33f0b..db652efded 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -52,26 +52,31 @@ size_t get_console_inputs(uint8_t* buf, size_t bufsize) void cdc_app_task(void) { uint8_t buf[64+1]; // +1 for extra null character - memset(buf, 0, sizeof(buf)); + uint32_t const bufsize = sizeof(buf)-1; - size_t count = get_console_inputs(buf, sizeof(buf)-1); + uint32_t console_count = get_console_inputs(buf, bufsize); + buf[console_count] = 0; // loop over all mounted interfaces - for(size_t idx=0; idx cdc interfaces - if (count) + if (console_count) { - tuh_cdc_write(idx, buf, count); + tuh_cdc_write(idx, buf, console_count); tuh_cdc_write_flush(idx); } // cdc interfaces -> console if ( tuh_cdc_read_available(idx) ) { - printf((char*) buf); + uint8_t buf_cdc[64+1]; + uint32_t cdc_count = tuh_cdc_read(idx, buf_cdc, sizeof(buf_cdc)-1); + buf_cdc[cdc_count] = 0; + + printf((char*) buf_cdc); } } } diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index f8d996e174..3265676893 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -459,7 +459,8 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t } else if ( ep_addr == p_cdc->stream.rx.ep_addr ) { - tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); + // skip if ZLP + if (xferred_bytes) tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); // invoke receive callback From edc559cb4d9c0c940387b514f2e66c4a2f3a9c1c Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 12:29:51 +0700 Subject: [PATCH 16/28] fix ci --- src/device/usbd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/device/usbd.c b/src/device/usbd.c index f9a7af21be..f652a878ef 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -39,13 +39,13 @@ // USBD Configuration //--------------------------------------------------------------------+ -// Debug level of USBD -#define USBD_DBG 2 - #ifndef CFG_TUD_TASK_QUEUE_SZ #define CFG_TUD_TASK_QUEUE_SZ 16 #endif +// Debug level of USBD +#define USBD_DBG 2 + //--------------------------------------------------------------------+ // Device Data //--------------------------------------------------------------------+ @@ -506,7 +506,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) break; case DCD_EVENT_SETUP_RECEIVED: - TU_LOG_VAR(USBD_DBG, &event.setup_received); + TU_LOG_PTR(USBD_DBG, &event.setup_received); TU_LOG(USBD_DBG, "\r\n"); // Mark as connected after receiving 1st setup packet. From 84a483f5ea7446a5cc1a9fe957379dd1f0a6fd4c Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 12:47:00 +0700 Subject: [PATCH 17/28] add more host cdc API tuh_cdc_write_available(), tuh_cdc_read_flush(), tuh_cdc_rx_cb() callback --- examples/host/cdc_msc_hid/src/cdc_app.c | 31 +++++++------ src/class/cdc/cdc_host.c | 34 ++++++++++++++ src/class/cdc/cdc_host.h | 62 +++++++++---------------- 3 files changed, 72 insertions(+), 55 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index db652efded..23ea05b2b6 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -54,8 +54,8 @@ void cdc_app_task(void) uint8_t buf[64+1]; // +1 for extra null character uint32_t const bufsize = sizeof(buf)-1; - uint32_t console_count = get_console_inputs(buf, bufsize); - buf[console_count] = 0; + uint32_t count = get_console_inputs(buf, bufsize); + buf[count] = 0; // loop over all mounted interfaces for(uint8_t idx=0; idx cdc interfaces - if (console_count) + if (count) { - tuh_cdc_write(idx, buf, console_count); + tuh_cdc_write(idx, buf, count); tuh_cdc_write_flush(idx); } - - // cdc interfaces -> console - if ( tuh_cdc_read_available(idx) ) - { - uint8_t buf_cdc[64+1]; - uint32_t cdc_count = tuh_cdc_read(idx, buf_cdc, sizeof(buf_cdc)-1); - buf_cdc[cdc_count] = 0; - - printf((char*) buf_cdc); - } } } } +// Invoked when received new data +void tuh_cdc_rx_cb(uint8_t idx) +{ + uint8_t buf[64+1]; // +1 for extra null character + uint32_t const bufsize = sizeof(buf)-1; + + // forward cdc interfaces -> console + uint32_t count = tuh_cdc_read(idx, buf, bufsize); + buf[count] = 0; + + printf((char*) buf); +} + void tuh_cdc_mount_cb(uint8_t idx) { tuh_cdc_itf_info_t itf_info; diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 3265676893..ba2e9e1b7d 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -185,6 +185,17 @@ uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t* s) return (uint32_t) tu_fifo_count(&s->ff); } +uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) +{ + return (uint32_t) tu_fifo_remaining(&s->ff); +} + +void tu_edpt_stream_read_clear(uint8_t daddr, tu_edpt_stream_t* s) +{ + tu_fifo_clear(&s->ff); + tu_edpt_stream_read_xfer(daddr, s); +} + typedef struct { uint8_t daddr; uint8_t bInterfaceNumber; @@ -227,6 +238,12 @@ static inline cdch_interface_t* get_itf(uint8_t idx) return (p_cdc->daddr != 0) ? p_cdc : NULL; } +TU_ATTR_ALWAYS_INLINE +static inline uint8_t itf2idx(cdch_interface_t* p_cdc) +{ + return (uint8_t) (p_cdc - cdch_data); +} + static inline cdch_interface_t* get_itf_by_ep_addr(uint8_t daddr, uint8_t ep_addr) { for(uint8_t i=0; idaddr, &p_cdc->stream.tx); } +uint32_t tuh_cdc_write_available(uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return tu_edpt_stream_write_available(&p_cdc->stream.tx); +} + uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) { cdch_interface_t* p_cdc = get_itf(idx); @@ -336,6 +361,14 @@ uint32_t tuh_cdc_read_available(uint8_t idx) return tu_edpt_stream_read_available(&p_cdc->stream.rx); } +void tuh_cdc_read_flush (uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc, ); + + tu_edpt_stream_read_clear(p_cdc->daddr, &p_cdc->stream.rx); +} + //--------------------------------------------------------------------+ // Control Endpoint API //--------------------------------------------------------------------+ @@ -463,6 +496,7 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t if (xferred_bytes) tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); // invoke receive callback + if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(itf2idx(p_cdc)); // prepare for next transfer if needed tu_edpt_stream_read_xfer(daddr, &p_cdc->stream.rx); diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 54e082e7d7..dd8ae80ced 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -97,18 +97,32 @@ TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) return tuh_cdc_get_dtr(idx); } +//--------------------------------------------------------------------+ +// Write API +//--------------------------------------------------------------------+ + +// Get the number of bytes available for writing +uint32_t tuh_cdc_write_available(uint8_t idx); + // Write to cdc interface uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize); // Force sending data if possible, return number of forced bytes uint32_t tuh_cdc_write_flush(uint8_t idx); -// Read from cdc interface -uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize); +//--------------------------------------------------------------------+ +// Read API +//--------------------------------------------------------------------+ // Get the number of bytes available for reading uint32_t tuh_cdc_read_available(uint8_t idx); +// Read from cdc interface +uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize); + +// Clear the received FIFO +void tuh_cdc_read_flush (uint8_t idx); + //--------------------------------------------------------------------+ // Control Endpoint (Request) API //--------------------------------------------------------------------+ @@ -132,47 +146,13 @@ static inline bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, ui // Invoked when a device with CDC interface is mounted // idx is index of cdc interface in the internal pool. -TU_ATTR_WEAK void tuh_cdc_mount_cb(uint8_t idx); +TU_ATTR_WEAK extern void tuh_cdc_mount_cb(uint8_t idx); // Invoked when a device with CDC interface is unmounted -TU_ATTR_WEAK void tuh_cdc_umount_cb(uint8_t idx); - -/** \brief Check if the interface is currently busy or not - * \param[in] dev_addr device address - * \param[in] pipeid value from \ref cdc_pipeid_t to indicate target pipe. - * \retval true if the interface is busy, meaning the stack is still transferring/waiting data from/to device - * \retval false if the interface is not busy, meaning the stack successfully transferred data from/to device - * \note This function is used to check if previous transfer is complete (success or error), so that the next transfer - * can be scheduled. User needs to make sure the corresponding interface is mounted - * (by \ref tuh_cdc_serial_is_mounted) before calling this function. - */ -// bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid); - -/** \brief Perform USB OUT transfer to device - * \param[in] dev_addr device address - * \param[in] p_data Buffer containing data. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION) - * \param[in] length Number of bytes to be transferred via USB bus - * \retval TUSB_ERROR_NONE on success - * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device - * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request) - * \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct - * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the - * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION. - */ -// bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify); - -/** \brief Perform USB IN transfer to get data from device - * \param[in] dev_addr device address - * \param[in] p_buffer Buffer containing received data. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION) - * \param[in] length Number of bytes to be transferred via USB bus - * \retval TUSB_ERROR_NONE on success - * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device - * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request) - * \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct - * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the - * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION. - */ -// bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify); +TU_ATTR_WEAK extern void tuh_cdc_umount_cb(uint8_t idx); + +// Invoked when received new data +TU_ATTR_WEAK extern void tuh_cdc_rx_cb(uint8_t idx); //--------------------------------------------------------------------+ // CDC APPLICATION CALLBACKS From cd9008e5a9c8da81d9736f7e0bf72c5ba409a7f1 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 13:05:45 +0700 Subject: [PATCH 18/28] add tuh_cdc_tx_complete_cb() callback --- examples/host/cdc_msc_hid/src/cdc_app.c | 4 ++-- src/class/cdc/cdc_host.c | 20 +++++++++----------- src/class/cdc/cdc_host.h | 3 +++ 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index 23ea05b2b6..dd3196146e 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -87,7 +87,7 @@ void tuh_cdc_rx_cb(uint8_t idx) void tuh_cdc_mount_cb(uint8_t idx) { - tuh_cdc_itf_info_t itf_info; + tuh_cdc_itf_info_t itf_info = { 0 }; tuh_cdc_itf_get_info(idx, &itf_info); printf("CDC Interface is mounted: device address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.bInterfaceNumber); @@ -95,7 +95,7 @@ void tuh_cdc_mount_cb(uint8_t idx) void tuh_cdc_umount_cb(uint8_t idx) { - tuh_cdc_itf_info_t itf_info; + tuh_cdc_itf_info_t itf_info = { 0 }; tuh_cdc_itf_get_info(idx, &itf_info); printf("CDC Interface is unmounted: device address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.bInterfaceNumber); diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index ba2e9e1b7d..ce0efe6e30 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -238,13 +238,7 @@ static inline cdch_interface_t* get_itf(uint8_t idx) return (p_cdc->daddr != 0) ? p_cdc : NULL; } -TU_ATTR_ALWAYS_INLINE -static inline uint8_t itf2idx(cdch_interface_t* p_cdc) -{ - return (uint8_t) (p_cdc - cdch_data); -} - -static inline cdch_interface_t* get_itf_by_ep_addr(uint8_t daddr, uint8_t ep_addr) +static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) { for(uint8_t i=0; idaddr == daddr) && (ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr)) { - return p_cdc; + return i; } } - return NULL; + return TUSB_INDEX_INVALID; } @@ -478,11 +472,15 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t // TODO handle stall response, retry failed transfer ... TU_ASSERT(event == XFER_RESULT_SUCCESS); - cdch_interface_t * p_cdc = get_itf_by_ep_addr(daddr, ep_addr); + uint8_t const idx = get_idx_by_ep_addr(daddr, ep_addr); + cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc); if ( ep_addr == p_cdc->stream.tx.ep_addr ) { + // invoke tx complete callback to possibly refill tx fifo + if (tuh_cdc_tx_complete_cb) tuh_cdc_tx_complete_cb(idx); + if ( 0 == tu_edpt_stream_write_xfer(daddr, &p_cdc->stream.tx) ) { // If there is no data left, a ZLP should be sent if needed @@ -496,7 +494,7 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t if (xferred_bytes) tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); // invoke receive callback - if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(itf2idx(p_cdc)); + if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(idx); // prepare for next transfer if needed tu_edpt_stream_read_xfer(daddr, &p_cdc->stream.rx); diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index dd8ae80ced..476431cc50 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -154,6 +154,9 @@ TU_ATTR_WEAK extern void tuh_cdc_umount_cb(uint8_t idx); // Invoked when received new data TU_ATTR_WEAK extern void tuh_cdc_rx_cb(uint8_t idx); +// Invoked when a TX is complete and therefore space becomes available in TX buffer +TU_ATTR_WEAK extern void tuh_cdc_tx_complete_cb(uint8_t idx); + //--------------------------------------------------------------------+ // CDC APPLICATION CALLBACKS //--------------------------------------------------------------------+ From 9e8ea44925e80abd7189ed7a673762527ee3adfd Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 17:46:11 +0700 Subject: [PATCH 19/28] add tuh_cdc_write_clear, rename read_flush() to read_clear() --- src/class/cdc/cdc_host.c | 24 +++++++++++++++++++----- src/class/cdc/cdc_host.h | 5 ++++- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index ce0efe6e30..2f34063786 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -190,10 +190,16 @@ uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) return (uint32_t) tu_fifo_remaining(&s->ff); } -void tu_edpt_stream_read_clear(uint8_t daddr, tu_edpt_stream_t* s) +bool tu_edpt_stream_read_clear(uint8_t daddr, tu_edpt_stream_t* s) { - tu_fifo_clear(&s->ff); + bool ret = tu_fifo_clear(&s->ff); tu_edpt_stream_read_xfer(daddr, s); + return ret; +} + +bool tu_edpt_stream_write_clear(tu_edpt_stream_t* s) +{ + return tu_fifo_clear(&s->ff); } typedef struct { @@ -331,6 +337,14 @@ uint32_t tuh_cdc_write_flush(uint8_t idx) return tu_edpt_stream_write_xfer(p_cdc->daddr, &p_cdc->stream.tx); } +bool tuh_cdc_write_clear(uint8_t idx) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return tu_edpt_stream_write_clear(&p_cdc->stream.tx); +} + uint32_t tuh_cdc_write_available(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); @@ -355,12 +369,12 @@ uint32_t tuh_cdc_read_available(uint8_t idx) return tu_edpt_stream_read_available(&p_cdc->stream.rx); } -void tuh_cdc_read_flush (uint8_t idx) +bool tuh_cdc_read_clear (uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); - TU_VERIFY(p_cdc, ); + TU_VERIFY(p_cdc); - tu_edpt_stream_read_clear(p_cdc->daddr, &p_cdc->stream.rx); + return tu_edpt_stream_read_clear(p_cdc->daddr, &p_cdc->stream.rx); } //--------------------------------------------------------------------+ diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 476431cc50..02ae691114 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -110,6 +110,9 @@ uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize); // Force sending data if possible, return number of forced bytes uint32_t tuh_cdc_write_flush(uint8_t idx); +// Clear the transmit FIFO +bool tuh_cdc_write_clear(uint8_t idx); + //--------------------------------------------------------------------+ // Read API //--------------------------------------------------------------------+ @@ -121,7 +124,7 @@ uint32_t tuh_cdc_read_available(uint8_t idx); uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize); // Clear the received FIFO -void tuh_cdc_read_flush (uint8_t idx); +bool tuh_cdc_read_clear (uint8_t idx); //--------------------------------------------------------------------+ // Control Endpoint (Request) API From 8323e4b79a2052aee814ca8811e841bceb6a7a7d Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 22 Dec 2022 00:34:35 +0700 Subject: [PATCH 20/28] moving edpt_stream API into common tusb.c --- src/class/cdc/cdc_host.c | 179 ++++++++---------------------------- src/common/tusb_private.h | 92 +++++++++++++++++- src/host/usbh.c | 1 - src/host/usbh_classdriver.h | 1 + src/tusb.c | 112 +++++++++++++++++++++- 5 files changed, 239 insertions(+), 146 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 2f34063786..54d81dc0d7 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -42,56 +42,23 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -typedef struct { - tu_fifo_t ff; - - // mutex: read if ep rx, write if e tx - OSAL_MUTEX_DEF(ff_mutex); - - // TODO xfer_fifo can skip this buffer - uint8_t* ep_buf; - uint16_t ep_bufsize; - uint8_t ep_addr; -}tu_edpt_stream_t; - -bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool use_wr_mutex, bool overwritable, - void* ff_buf, uint16_t ff_bufsize, - uint8_t* ep_buf, uint16_t ep_bufsize) -{ - osal_mutex_t new_mutex = osal_mutex_create(&s->ff_mutex); - (void) new_mutex; - (void) use_wr_mutex; - - tu_fifo_config(&s->ff, ff_buf, ff_bufsize, 1, overwritable); - tu_fifo_config_mutex(&s->ff, use_wr_mutex ? new_mutex : NULL, use_wr_mutex ? NULL : new_mutex); - - s->ep_buf = ep_buf; - s->ep_bufsize = ep_bufsize; - - return true; -} - -bool tu_edpt_stream_clear(tu_edpt_stream_t* s) -{ - return tu_fifo_clear(&s->ff); -} -bool tu_edpt_stream_write_zlp_if_needed(uint8_t daddr, tu_edpt_stream_t* s, uint32_t last_xferred_bytes) +bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes) { - uint16_t const bulk_packet_size = (tuh_speed_get(daddr) == TUSB_SPEED_HIGH) ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; + uint16_t const bulk_packet_size = (s->ep_speed == TUSB_SPEED_HIGH) ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; // ZLP condition: no pending data, last transferred bytes is multiple of packet size TU_VERIFY( !tu_fifo_count(&s->ff) && last_xferred_bytes && (0 == (last_xferred_bytes & (bulk_packet_size-1))) ); - if ( usbh_edpt_claim(daddr, s->ep_addr) ) + if ( usbh_edpt_claim(s->daddr, s->ep_addr) ) { - TU_ASSERT( usbh_edpt_xfer(daddr, s->ep_addr, NULL, 0) ); + TU_ASSERT( usbh_edpt_xfer(s->daddr, s->ep_addr, NULL, 0) ); } return true; } -uint32_t tu_edpt_stream_write_xfer(uint8_t daddr, tu_edpt_stream_t* s) +uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) { // skip if no data TU_VERIFY( tu_fifo_count(&s->ff), 0 ); @@ -99,7 +66,7 @@ uint32_t tu_edpt_stream_write_xfer(uint8_t daddr, tu_edpt_stream_t* s) // Claim the endpoint // uint8_t const rhport = 0; // TU_VERIFY( usbd_edpt_claim(rhport, p_cdc->ep_in), 0 ); - TU_VERIFY( usbh_edpt_claim(daddr, s->ep_addr) ); + TU_VERIFY( usbh_edpt_claim(s->daddr, s->ep_addr) ); // Pull data from FIFO -> EP buf uint16_t const count = tu_fifo_read_n(&s->ff, s->ep_buf, s->ep_bufsize); @@ -107,7 +74,7 @@ uint32_t tu_edpt_stream_write_xfer(uint8_t daddr, tu_edpt_stream_t* s) if ( count ) { //TU_ASSERT( usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 ); - TU_ASSERT( usbh_edpt_xfer(daddr, s->ep_addr, s->ep_buf, count), 0 ); + TU_ASSERT( usbh_edpt_xfer(s->daddr, s->ep_addr, s->ep_buf, count), 0 ); return count; }else { @@ -115,93 +82,28 @@ uint32_t tu_edpt_stream_write_xfer(uint8_t daddr, tu_edpt_stream_t* s) // Note: data is dropped if terminal is not connected //usbd_edpt_release(rhport, p_cdc->ep_in); - usbh_edpt_release(daddr, s->ep_addr); + usbh_edpt_release(s->daddr, s->ep_addr); return 0; } } -uint32_t tu_edpt_stream_write(uint8_t daddr, tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize) -{ - uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); - - // flush if queue more than packet size - uint16_t const bulk_packet_size = (tuh_speed_get(daddr) == TUSB_SPEED_HIGH) ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; - if ( (tu_fifo_count(&s->ff) >= bulk_packet_size) - /* || ((CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE) && tu_fifo_full(&p_cdc->tx_ff)) */ ) - { - tu_edpt_stream_write_xfer(daddr, s); - } - - return ret; -} - -void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) -{ - tu_fifo_write_n(&s->ff, s->ep_buf, (uint16_t) xferred_bytes); -} - -uint32_t tu_edpt_stream_read_xfer(uint8_t daddr, tu_edpt_stream_t* s) +uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize) { - uint16_t available = tu_fifo_remaining(&s->ff); + TU_VERIFY(bufsize); // TODO support ZLP - // 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 - uint16_t const bulk_packet_size = (tuh_speed_get(daddr) == TUSB_SPEED_HIGH) ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; - TU_VERIFY(available >= bulk_packet_size); - - // claim endpoint - TU_VERIFY(usbh_edpt_claim(daddr, s->ep_addr), 0); - - // fifo can be changed before endpoint is claimed - available = tu_fifo_remaining(&s->ff); - - if ( available >= bulk_packet_size ) - { - // multiple of packet size limit by ep bufsize - uint16_t count = (uint16_t) (available & (bulk_packet_size -1)); - count = tu_min16(count, s->ep_bufsize); + uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); - TU_ASSERT( usbh_edpt_xfer(daddr, s->ep_addr, s->ep_buf, count), 0 ); - return count; - }else + // flush if fifo has more than packet size or + // in rare case: fifo depth is configured too small (which never reach packet size) + uint16_t const bulk_packet_size = (s->ep_speed == TUSB_SPEED_HIGH) ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; + if ( (tu_fifo_count(&s->ff) >= bulk_packet_size) || ( tu_fifo_depth(&s->ff) < bulk_packet_size) ) { - // Release endpoint since we don't make any transfer - usbh_edpt_release(daddr, s->ep_addr); - return 0; + tu_edpt_stream_write_xfer(s); } -} - -uint32_t tu_edpt_stream_read(uint8_t daddr, tu_edpt_stream_t* s, void* buffer, uint32_t bufsize) -{ - uint32_t num_read = tu_fifo_read_n(&s->ff, buffer, (uint16_t) bufsize); - tu_edpt_stream_read_xfer(daddr, s); - return num_read; -} - -uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t* s) -{ - return (uint32_t) tu_fifo_count(&s->ff); -} - -uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) -{ - return (uint32_t) tu_fifo_remaining(&s->ff); -} -bool tu_edpt_stream_read_clear(uint8_t daddr, tu_edpt_stream_t* s) -{ - bool ret = tu_fifo_clear(&s->ff); - tu_edpt_stream_read_xfer(daddr, s); return ret; } -bool tu_edpt_stream_write_clear(tu_edpt_stream_t* s) -{ - return tu_fifo_clear(&s->ff); -} - typedef struct { uint8_t daddr; uint8_t bInterfaceNumber; @@ -326,7 +228,7 @@ uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_write(p_cdc->daddr, &p_cdc->stream.tx, buffer, bufsize); + return tu_edpt_stream_write(&p_cdc->stream.tx, buffer, bufsize); } uint32_t tuh_cdc_write_flush(uint8_t idx) @@ -334,7 +236,7 @@ uint32_t tuh_cdc_write_flush(uint8_t idx) cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_write_xfer(p_cdc->daddr, &p_cdc->stream.tx); + return tu_edpt_stream_write_xfer(&p_cdc->stream.tx); } bool tuh_cdc_write_clear(uint8_t idx) @@ -342,7 +244,7 @@ bool tuh_cdc_write_clear(uint8_t idx) cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_write_clear(&p_cdc->stream.tx); + return tu_edpt_stream_clear(&p_cdc->stream.tx); } uint32_t tuh_cdc_write_available(uint8_t idx) @@ -358,7 +260,7 @@ uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_read(p_cdc->daddr, &p_cdc->stream.rx, buffer, bufsize); + return tu_edpt_stream_read(&p_cdc->stream.rx, buffer, bufsize); } uint32_t tuh_cdc_read_available(uint8_t idx) @@ -374,7 +276,9 @@ bool tuh_cdc_read_clear (uint8_t idx) cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_read_clear(p_cdc->daddr, &p_cdc->stream.rx); + bool ret = tu_edpt_stream_clear(&p_cdc->stream.rx); + tu_edpt_stream_read_xfer(&p_cdc->stream.rx); + return ret; } //--------------------------------------------------------------------+ @@ -452,13 +356,13 @@ void cdch_init(void) { cdch_interface_t* p_cdc = &cdch_data[i]; - tu_edpt_stream_init(&p_cdc->stream.tx, true, false, - p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, - p_cdc->stream.tx_ep_buf, CFG_TUH_CDC_TX_EPSIZE); + tu_edpt_stream_init(&p_cdc->stream.tx, true, true, false, + p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, + p_cdc->stream.tx_ep_buf, CFG_TUH_CDC_TX_EPSIZE); - tu_edpt_stream_init(&p_cdc->stream.rx, false, false, - p_cdc->stream.rx_ff_buf, CFG_TUH_CDC_RX_BUFSIZE, - p_cdc->stream.rx_ep_buf, CFG_TUH_CDC_RX_EPSIZE); + tu_edpt_stream_init(&p_cdc->stream.rx, true, false, false, + p_cdc->stream.rx_ff_buf, CFG_TUH_CDC_RX_BUFSIZE, + p_cdc->stream.rx_ep_buf, CFG_TUH_CDC_RX_EPSIZE); } } @@ -475,8 +379,6 @@ void cdch_close(uint8_t daddr) //tu_memclr(p_cdc, sizeof(cdch_interface_t)); p_cdc->daddr = 0; p_cdc->bInterfaceNumber = 0; - tu_edpt_stream_clear(&p_cdc->stream.tx); - tu_edpt_stream_clear(&p_cdc->stream.rx); } } } @@ -495,23 +397,22 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t // invoke tx complete callback to possibly refill tx fifo if (tuh_cdc_tx_complete_cb) tuh_cdc_tx_complete_cb(idx); - if ( 0 == tu_edpt_stream_write_xfer(daddr, &p_cdc->stream.tx) ) + if ( 0 == tu_edpt_stream_write_xfer(&p_cdc->stream.tx) ) { // If there is no data left, a ZLP should be sent if needed // 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); + tu_edpt_stream_write_zlp_if_needed(&p_cdc->stream.tx, xferred_bytes); } } else if ( ep_addr == p_cdc->stream.rx.ep_addr ) { - // skip if ZLP - if (xferred_bytes) tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); + tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); // invoke receive callback if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(idx); // prepare for next transfer if needed - tu_edpt_stream_read_xfer(daddr, &p_cdc->stream.rx); + tu_edpt_stream_read_xfer(&p_cdc->stream.rx); }else if ( ep_addr == p_cdc->ep_notif ) { // TODO handle notification endpoint @@ -527,7 +428,7 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t // Enumeration //--------------------------------------------------------------------+ -bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) +bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { (void) rhport; @@ -542,7 +443,7 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it cdch_interface_t * p_cdc = find_new_itf(); TU_VERIFY(p_cdc); - p_cdc->daddr = dev_addr; + p_cdc->daddr = daddr; p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber; p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol; @@ -569,7 +470,7 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)); tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; - TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) ); + TU_ASSERT( tuh_edpt_open(daddr, desc_ep) ); p_cdc->ep_notif = desc_ep->bEndpointAddress; p_desc = tu_desc_next(p_desc); @@ -589,14 +490,14 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); - TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep)); + TU_ASSERT(tuh_edpt_open(daddr, desc_ep)); if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) { - p_cdc->stream.rx.ep_addr = desc_ep->bEndpointAddress; + tu_edpt_stream_open(&p_cdc->stream.rx, daddr, desc_ep); }else { - p_cdc->stream.tx.ep_addr = desc_ep->bEndpointAddress; + tu_edpt_stream_open(&p_cdc->stream.tx, daddr, desc_ep); } p_desc = tu_desc_next(p_desc); @@ -616,7 +517,7 @@ static void config_cdc_complete(uint8_t daddr, uint8_t itf_num) // Prepare for incoming data cdch_interface_t* p_cdc = get_itf(idx); - tu_edpt_stream_read_xfer(daddr, &p_cdc->stream.rx); + tu_edpt_stream_read_xfer(&p_cdc->stream.rx); } // notify usbh that driver enumeration is complete diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index b34506f650..01078eed31 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -28,6 +28,8 @@ #ifndef _TUSB_PRIVATE_H_ #define _TUSB_PRIVATE_H_ +// Internal Helper used by Host and Device Stack + #ifdef __cplusplus extern "C" { #endif @@ -39,8 +41,31 @@ typedef struct TU_ATTR_PACKED volatile uint8_t claimed : 1; }tu_edpt_state_t; +typedef struct { + bool is_host; // host or device most + union { + uint8_t daddr; + uint8_t rhport; + uint8_t hwid; + }; + uint8_t ep_addr; + uint8_t ep_speed; + + uint16_t ep_packetsize; + uint16_t ep_bufsize; + + // TODO xfer_fifo can skip this buffer + uint8_t* ep_buf; + + tu_fifo_t ff; + + // mutex: read if ep rx, write if e tx + OSAL_MUTEX_DEF(ff_mutex); + +}tu_edpt_stream_t; + //--------------------------------------------------------------------+ -// Internal Helper used by Host and Device Stack +// Endpoint //--------------------------------------------------------------------+ // Check if endpoint descriptor is valid per USB specs @@ -58,6 +83,71 @@ bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex); // Release an endpoint with provided mutex bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex); +//--------------------------------------------------------------------+ +// Endpoint Stream +//--------------------------------------------------------------------+ + +// Init an stream, should only called once +bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool overwritable, + void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize); + +// Open an stream for an endpoint +// hwid is either device address (host mode) or rhport (device mode) +TU_ATTR_ALWAYS_INLINE static inline +void tu_edpt_stream_open(tu_edpt_stream_t* s, uint8_t hwid, tusb_desc_endpoint_t const *desc_ep) +{ + tu_fifo_clear(&s->ff); + s->hwid = hwid; + s->ep_addr = desc_ep->bEndpointAddress; + s->ep_packetsize = tu_edpt_packet_size(desc_ep); +} + +// Clear fifo +TU_ATTR_ALWAYS_INLINE static inline +bool tu_edpt_stream_clear(tu_edpt_stream_t* s) +{ + return tu_fifo_clear(&s->ff); +} + +//------------- Write -------------// + +// Write to stream +uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize); + +// Start an usb transfer if endpoint is not busy +uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s); + +// Get the number of bytes available for writing +TU_ATTR_ALWAYS_INLINE static inline +uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) +{ + return (uint32_t) tu_fifo_remaining(&s->ff); +} + + +//------------- Read -------------// + +// Read from stream +uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize); + +// Start an usb transfer if endpoint is not busy +uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s); + +// Must be called in the transfer complete callback +TU_ATTR_ALWAYS_INLINE static inline +void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) +{ + tu_fifo_write_n(&s->ff, s->ep_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) +{ + return (uint32_t) tu_fifo_count(&s->ff); +} + + #ifdef __cplusplus } #endif diff --git a/src/host/usbh.c b/src/host/usbh.c index 36fc5fded8..f0ca7be2ed 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -30,7 +30,6 @@ #include "host/hcd.h" #include "tusb.h" -#include "common/tusb_private.h" #include "host/usbh_classdriver.h" #include "hub.h" diff --git a/src/host/usbh_classdriver.h b/src/host/usbh_classdriver.h index 7f72560c32..be9811641e 100644 --- a/src/host/usbh_classdriver.h +++ b/src/host/usbh_classdriver.h @@ -29,6 +29,7 @@ #include "osal/osal.h" #include "common/tusb_fifo.h" +#include "common/tusb_private.h" #ifdef __cplusplus extern "C" { diff --git a/src/tusb.c b/src/tusb.c index f4380f89c9..05e0d4c1fb 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -31,11 +31,18 @@ #include "tusb.h" #include "common/tusb_private.h" -// TODO clean up #if CFG_TUD_ENABLED #include "device/usbd_pvt.h" #endif +#if CFG_TUH_ENABLED +#include "host/usbh_classdriver.h" +#endif + +//--------------------------------------------------------------------+ +// Public API +//--------------------------------------------------------------------+ + bool tusb_init(void) { #if CFG_TUD_ENABLED && defined(TUD_OPT_RHPORT) @@ -67,7 +74,7 @@ bool tusb_inited(void) } //--------------------------------------------------------------------+ -// Internal Helper for both Host and Device stack +// Endpoint Helper for both Host and Device stack //--------------------------------------------------------------------+ bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex) @@ -196,9 +203,104 @@ uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, return len; } -/*------------------------------------------------------------------*/ -/* Debug - *------------------------------------------------------------------*/ +//--------------------------------------------------------------------+ +// Endpoint Stream Helper for both Host and Device stack +//--------------------------------------------------------------------+ + +bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool overwritable, + void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize) +{ + osal_mutex_t new_mutex = osal_mutex_create(&s->ff_mutex); + (void) new_mutex; + (void) is_tx; + + s->is_host = is_host; + tu_fifo_config(&s->ff, ff_buf, ff_bufsize, 1, overwritable); + tu_fifo_config_mutex(&s->ff, is_tx ? new_mutex : NULL, is_tx ? NULL : new_mutex); + + s->ep_buf = ep_buf; + s->ep_bufsize = ep_bufsize; + + return true; +} + +//------------- Stream Write -------------// + +//------------- Stream Read -------------// + +uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) +{ + uint16_t available = tu_fifo_remaining(&s->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 >= s->ep_packetsize); + + // claim endpoint + if (s->is_host) + { + #if CFG_TUH_ENABLED + TU_VERIFY(usbh_edpt_claim(s->daddr, s->ep_addr), 0); + #endif + }else + { + #if CFG_TUD_ENABLED + TU_VERIFY(usbd_edpt_claim(s->rhport, s->ep_addr), 0); + #endif + } + + // get available again since fifo can be changed before endpoint is claimed + available = tu_fifo_remaining(&s->ff); + + if ( available >= s->ep_packetsize ) + { + // multiple of packet size limit by ep bufsize + uint16_t count = (uint16_t) (available & (s->ep_packetsize -1)); + count = tu_min16(count, s->ep_bufsize); + + if (s->is_host) + { + #if CFG_TUH_ENABLED + TU_ASSERT( usbh_edpt_xfer(s->daddr, s->ep_addr, s->ep_buf, count), 0 ); + #endif + }else + { + #if CFG_TUD_ENABLED + TU_ASSERT( usbd_edpt_xfer(s->rhport, s->ep_addr, s->ep_buf, count), 0 ); + #endif + } + return count; + }else + { + // Release endpoint since we don't make any transfer + if (s->is_host) + { + #if CFG_TUH_ENABLED + usbh_edpt_release(s->daddr, s->ep_addr); + #endif + }else + { + #if CFG_TUD_ENABLED + usbd_edpt_release(s->rhport, s->ep_addr); + #endif + } + + return 0; + } +} + +uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize) +{ + uint32_t num_read = tu_fifo_read_n(&s->ff, buffer, (uint16_t) bufsize); + tu_edpt_stream_read_xfer(s); + return num_read; +} + +//--------------------------------------------------------------------+ +// Debug +//--------------------------------------------------------------------+ #if CFG_TUSB_DEBUG #include From e3c9d9450009f757b9ddf5f94a00f14e7cfb0471 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 22 Dec 2022 11:16:39 +0700 Subject: [PATCH 21/28] fix stream read count computation --- src/class/cdc/cdc_host.c | 63 +------------------------ src/common/tusb_private.h | 21 +++++++-- src/tusb.c | 96 +++++++++++++++++++++++++++++++++------ 3 files changed, 101 insertions(+), 79 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 54d81dc0d7..469725e724 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -43,67 +43,6 @@ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes) -{ - uint16_t const bulk_packet_size = (s->ep_speed == TUSB_SPEED_HIGH) ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; - - // ZLP condition: no pending data, last transferred bytes is multiple of packet size - TU_VERIFY( !tu_fifo_count(&s->ff) && last_xferred_bytes && (0 == (last_xferred_bytes & (bulk_packet_size-1))) ); - - if ( usbh_edpt_claim(s->daddr, s->ep_addr) ) - { - TU_ASSERT( usbh_edpt_xfer(s->daddr, s->ep_addr, NULL, 0) ); - } - - return true; -} - -uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) -{ - // skip if no data - TU_VERIFY( tu_fifo_count(&s->ff), 0 ); - - // Claim the endpoint - // uint8_t const rhport = 0; - // TU_VERIFY( usbd_edpt_claim(rhport, p_cdc->ep_in), 0 ); - TU_VERIFY( usbh_edpt_claim(s->daddr, s->ep_addr) ); - - // Pull data from FIFO -> EP buf - uint16_t const count = tu_fifo_read_n(&s->ff, s->ep_buf, s->ep_bufsize); - - if ( count ) - { - //TU_ASSERT( usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 ); - TU_ASSERT( usbh_edpt_xfer(s->daddr, s->ep_addr, s->ep_buf, 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(rhport, p_cdc->ep_in); - - usbh_edpt_release(s->daddr, s->ep_addr); - return 0; - } -} - -uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize) -{ - TU_VERIFY(bufsize); // TODO support ZLP - - uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); - - // flush if fifo has more than packet size or - // in rare case: fifo depth is configured too small (which never reach packet size) - uint16_t const bulk_packet_size = (s->ep_speed == TUSB_SPEED_HIGH) ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; - if ( (tu_fifo_count(&s->ff) >= bulk_packet_size) || ( tu_fifo_depth(&s->ff) < bulk_packet_size) ) - { - tu_edpt_stream_write_xfer(s); - } - - return ret; -} - typedef struct { uint8_t daddr; uint8_t bInterfaceNumber; @@ -379,6 +318,8 @@ void cdch_close(uint8_t daddr) //tu_memclr(p_cdc, sizeof(cdch_interface_t)); p_cdc->daddr = 0; p_cdc->bInterfaceNumber = 0; + tu_edpt_stream_close(&p_cdc->stream.tx); + tu_edpt_stream_close(&p_cdc->stream.rx); } } } diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index 01078eed31..d0c7a84fb9 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -87,7 +87,7 @@ bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex); // Endpoint Stream //--------------------------------------------------------------------+ -// Init an stream, should only called once +// Init an stream, should only be called once bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool overwritable, void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize); @@ -102,6 +102,13 @@ void tu_edpt_stream_open(tu_edpt_stream_t* s, uint8_t hwid, tusb_desc_endpoint_t s->ep_packetsize = tu_edpt_packet_size(desc_ep); } +TU_ATTR_ALWAYS_INLINE static inline +void tu_edpt_stream_close(tu_edpt_stream_t* s) +{ + s->hwid = 0; + s->ep_addr = 0; +} + // Clear fifo TU_ATTR_ALWAYS_INLINE static inline bool tu_edpt_stream_clear(tu_edpt_stream_t* s) @@ -109,7 +116,9 @@ bool tu_edpt_stream_clear(tu_edpt_stream_t* s) return tu_fifo_clear(&s->ff); } -//------------- Write -------------// +//--------------------------------------------------------------------+ +// Stream Write +//--------------------------------------------------------------------+ // Write to stream uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize); @@ -117,6 +126,9 @@ uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const *buffer, uint32_t // Start an usb transfer if endpoint is not busy uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s); +// Start an zero-length packet if needed +bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes); + // Get the number of bytes available for writing TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) @@ -124,8 +136,9 @@ uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) return (uint32_t) tu_fifo_remaining(&s->ff); } - -//------------- Read -------------// +//--------------------------------------------------------------------+ +// Stream Read +//--------------------------------------------------------------------+ // Read from stream uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize); diff --git a/src/tusb.c b/src/tusb.c index 05e0d4c1fb..0d0e84a492 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -224,9 +224,86 @@ bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool ove return true; } -//------------- Stream Write -------------// +TU_ATTR_ALWAYS_INLINE static inline +bool stream_claim(tu_edpt_stream_t* s) +{ + if (s->is_host) + { + #if CFG_TUH_ENABLED + return usbh_edpt_claim(s->daddr, s->ep_addr); + #endif + }else + { + #if CFG_TUD_ENABLED + return usbd_edpt_claim(s->rhport, s->ep_addr); + #endif + } + + return false; +} -//------------- Stream Read -------------// + +//--------------------------------------------------------------------+ +// Stream Write +//--------------------------------------------------------------------+ + +bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes) +{ + // ZLP condition: no pending data, last transferred bytes is multiple of packet size + TU_VERIFY( !tu_fifo_count(&s->ff) && last_xferred_bytes && (0 == (last_xferred_bytes & (s->ep_packetsize-1))) ); + + TU_VERIFY( stream_claim(s) ); + TU_ASSERT( usbh_edpt_xfer(s->daddr, s->ep_addr, NULL, 0) ); + + return true; +} + +uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) +{ + // skip if no data + TU_VERIFY( tu_fifo_count(&s->ff), 0 ); + + // Claim the endpoint + TU_VERIFY( stream_claim(s), 0 ); + + // Pull data from FIFO -> EP buf + uint16_t const count = tu_fifo_read_n(&s->ff, s->ep_buf, s->ep_bufsize); + + if ( count ) + { + //TU_ASSERT( usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 ); + TU_ASSERT( usbh_edpt_xfer(s->daddr, s->ep_addr, s->ep_buf, 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(rhport, p_cdc->ep_in); + + usbh_edpt_release(s->daddr, s->ep_addr); + return 0; + } +} + +uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize) +{ + TU_VERIFY(bufsize); // TODO support ZLP + + uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); + + // flush if fifo has more than packet size or + // in rare case: fifo depth is configured too small (which never reach packet size) + if ( (tu_fifo_count(&s->ff) >= s->ep_packetsize) || (tu_fifo_depth(&s->ff) < s->ep_packetsize) ) + { + tu_edpt_stream_write_xfer(s); + } + + return ret; +} + +//--------------------------------------------------------------------+ +// Stream Read +//--------------------------------------------------------------------+ uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) { @@ -239,17 +316,7 @@ uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) TU_VERIFY(available >= s->ep_packetsize); // claim endpoint - if (s->is_host) - { - #if CFG_TUH_ENABLED - TU_VERIFY(usbh_edpt_claim(s->daddr, s->ep_addr), 0); - #endif - }else - { - #if CFG_TUD_ENABLED - TU_VERIFY(usbd_edpt_claim(s->rhport, s->ep_addr), 0); - #endif - } + TU_VERIFY(stream_claim(s), 0); // get available again since fifo can be changed before endpoint is claimed available = tu_fifo_remaining(&s->ff); @@ -257,7 +324,7 @@ uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) if ( available >= s->ep_packetsize ) { // multiple of packet size limit by ep bufsize - uint16_t count = (uint16_t) (available & (s->ep_packetsize -1)); + uint16_t count = (uint16_t) (available & ~(s->ep_packetsize -1)); count = tu_min16(count, s->ep_bufsize); if (s->is_host) @@ -301,6 +368,7 @@ uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize //--------------------------------------------------------------------+ // Debug //--------------------------------------------------------------------+ + #if CFG_TUSB_DEBUG #include From 2d536123c8ff8dd233656f0a9d7c16aff606302d Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 22 Dec 2022 11:31:37 +0700 Subject: [PATCH 22/28] finish moving edpt stream to tusb.c --- src/class/cdc/cdc_host.c | 4 +-- src/tusb.c | 69 ++++++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 30 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 469725e724..de1466cb18 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -340,8 +340,8 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t if ( 0 == tu_edpt_stream_write_xfer(&p_cdc->stream.tx) ) { - // If there is no data left, a ZLP should be sent if needed - // xferred_bytes is multiple of EP Packet size and not zero + // 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(&p_cdc->stream.tx, xferred_bytes); } } diff --git a/src/tusb.c b/src/tusb.c index 0d0e84a492..8f64f4acf8 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -242,6 +242,41 @@ bool stream_claim(tu_edpt_stream_t* s) return false; } +TU_ATTR_ALWAYS_INLINE static inline +bool stream_xfer(tu_edpt_stream_t* s, uint16_t count) +{ + if (s->is_host) + { + #if CFG_TUH_ENABLED + return usbh_edpt_xfer(s->daddr, s->ep_addr, count ? s->ep_buf : NULL, count); + #endif + }else + { + #if CFG_TUD_ENABLED + return usbd_edpt_xfer(s->rhport, s->ep_addr, cont ? s->ep_buf : NULL, count); + #endif + } + + return false; +} + +TU_ATTR_ALWAYS_INLINE static inline +bool stream_release(tu_edpt_stream_t* s) +{ + if (s->is_host) + { + #if CFG_TUH_ENABLED + return usbh_edpt_release(s->daddr, s->ep_addr); + #endif + }else + { + #if CFG_TUD_ENABLED + return usbd_edpt_release(s->rhport, s->ep_addr); + #endif + } + + return false; +} //--------------------------------------------------------------------+ // Stream Write @@ -253,7 +288,7 @@ bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferr TU_VERIFY( !tu_fifo_count(&s->ff) && last_xferred_bytes && (0 == (last_xferred_bytes & (s->ep_packetsize-1))) ); TU_VERIFY( stream_claim(s) ); - TU_ASSERT( usbh_edpt_xfer(s->daddr, s->ep_addr, NULL, 0) ); + TU_ASSERT( stream_xfer(s, 0) ); return true; } @@ -271,16 +306,13 @@ uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) if ( count ) { - //TU_ASSERT( usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 ); - TU_ASSERT( usbh_edpt_xfer(s->daddr, s->ep_addr, s->ep_buf, count), 0 ); + TU_ASSERT( stream_xfer(s, 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(rhport, p_cdc->ep_in); - - usbh_edpt_release(s->daddr, s->ep_addr); + stream_release(s); return 0; } } @@ -327,32 +359,13 @@ uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) uint16_t count = (uint16_t) (available & ~(s->ep_packetsize -1)); count = tu_min16(count, s->ep_bufsize); - if (s->is_host) - { - #if CFG_TUH_ENABLED - TU_ASSERT( usbh_edpt_xfer(s->daddr, s->ep_addr, s->ep_buf, count), 0 ); - #endif - }else - { - #if CFG_TUD_ENABLED - TU_ASSERT( usbd_edpt_xfer(s->rhport, s->ep_addr, s->ep_buf, count), 0 ); - #endif - } + TU_ASSERT( stream_xfer(s, count), 0 ); + return count; }else { // Release endpoint since we don't make any transfer - if (s->is_host) - { - #if CFG_TUH_ENABLED - usbh_edpt_release(s->daddr, s->ep_addr); - #endif - }else - { - #if CFG_TUD_ENABLED - usbd_edpt_release(s->rhport, s->ep_addr); - #endif - } + stream_release(s); return 0; } From c99af908f10103c0829c4adc1ef74832c3ca4482 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 22 Dec 2022 11:41:27 +0700 Subject: [PATCH 23/28] fix typo --- src/tusb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tusb.c b/src/tusb.c index 8f64f4acf8..a5c820b8d0 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -253,7 +253,7 @@ bool stream_xfer(tu_edpt_stream_t* s, uint16_t count) }else { #if CFG_TUD_ENABLED - return usbd_edpt_xfer(s->rhport, s->ep_addr, cont ? s->ep_buf : NULL, count); + return usbd_edpt_xfer(s->rhport, s->ep_addr, count ? s->ep_buf : NULL, count); #endif } @@ -366,7 +366,6 @@ uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) { // Release endpoint since we don't make any transfer stream_release(s); - return 0; } } From 11233e4d3e04ceab1ad6e33d37a166aa48c436de Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 22 Dec 2022 11:43:57 +0700 Subject: [PATCH 24/28] minor clean up --- examples/host/cdc_msc_hid/src/tusb_config.h | 4 +++ src/class/cdc/cdc_host.h | 28 ++++----------------- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index c515405cb8..e3d9356f67 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -108,6 +108,10 @@ #define CFG_TUH_HID_EPIN_BUFSIZE 64 #define CFG_TUH_HID_EPOUT_BUFSIZE 64 +//------------- CDC -------------// +// Set both DTR ( bit 0), RTS (bit 1) on enumeration/mounted +#define CFG_TUH_CDC_SET_DTRRTS_ON_ENUM 0x03 + #ifdef __cplusplus } #endif diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 02ae691114..5407c646d8 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -49,7 +49,7 @@ // RX Endpoint size #ifndef CFG_TUH_CDC_RX_EPSIZE -#define CFG_TUH_CDC_RX_EPSIZE USBH_EPSIZE_BULK_MAX +#define CFG_TUH_CDC_RX_EPSIZE USBH_EPSIZE_BULK_MAX #endif // TX FIFO size @@ -59,7 +59,7 @@ // TX Endpoint size #ifndef CFG_TUH_CDC_TX_EPSIZE -#define CFG_TUH_CDC_TX_EPSIZE USBH_EPSIZE_BULK_MAX +#define CFG_TUH_CDC_TX_EPSIZE USBH_EPSIZE_BULK_MAX #endif //--------------------------------------------------------------------+ @@ -145,7 +145,9 @@ static inline bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, ui return tuh_cdc_set_control_line_state(idx, 0x00, complete_cb, user_data); } -//------------- Application Callback -------------// +//--------------------------------------------------------------------+ +// CDC APPLICATION CALLBACKS +//--------------------------------------------------------------------+ // Invoked when a device with CDC interface is mounted // idx is index of cdc interface in the internal pool. @@ -160,26 +162,6 @@ TU_ATTR_WEAK extern void tuh_cdc_rx_cb(uint8_t idx); // Invoked when a TX is complete and therefore space becomes available in TX buffer TU_ATTR_WEAK extern void tuh_cdc_tx_complete_cb(uint8_t idx); -//--------------------------------------------------------------------+ -// CDC APPLICATION CALLBACKS -//--------------------------------------------------------------------+ - -/** \brief Callback function that is invoked when an transferring event occurred - * \param[in] dev_addr Address of device - * \param[in] event an value from \ref xfer_result_t - * \param[in] pipe_id value from \ref cdc_pipeid_t indicate the pipe - * \param[in] xferred_bytes Number of bytes transferred via USB bus - * \note event can be one of following - * - XFER_RESULT_SUCCESS : previously scheduled transfer completes successfully. - * - XFER_RESULT_FAILED : previously scheduled transfer encountered a transaction error. - * - XFER_RESULT_STALLED : previously scheduled transfer is stalled by device. - * \note - */ -// void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes); - -/// @} // group CDC_Serial_Host -/// @} - //--------------------------------------------------------------------+ // Internal Class Driver API //--------------------------------------------------------------------+ From 05c119ce975668eff814c78d5306589fc2d24530 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 22 Dec 2022 18:28:06 +0700 Subject: [PATCH 25/28] cdc host, add set line coding API --- examples/host/cdc_msc_hid/src/tusb_config.h | 11 +- src/class/cdc/cdc.h | 28 ++++- src/class/cdc/cdc_host.c | 129 +++++++++++++++----- src/class/cdc/cdc_host.h | 16 ++- 4 files changed, 143 insertions(+), 41 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index e3d9356f67..139a921d1a 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -109,8 +109,15 @@ #define CFG_TUH_HID_EPOUT_BUFSIZE 64 //------------- CDC -------------// -// Set both DTR ( bit 0), RTS (bit 1) on enumeration/mounted -#define CFG_TUH_CDC_SET_DTRRTS_ON_ENUM 0x03 + +// Set Line Control state on enumeration/mounted: +// DTR ( bit 0), RTS (bit 1) +#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03 + +// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t +// bit rate = 115200, 1 stop bit, no parity, 8 bit data width +#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } + #ifdef __cplusplus } diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index 6a9669cf24..9a3fc21ee5 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -198,6 +198,22 @@ enum CDC_CONTROL_LINE_STATE_RTS = 0x02, }; +enum +{ + CDC_LINE_CONDING_STOP_BITS_1 = 0, // 1 bit + CDC_LINE_CONDING_STOP_BITS_1_5 = 1, // 1.5 bits + CDC_LINE_CONDING_STOP_BITS_2 = 2, // 2 bits +}; + +enum +{ + CDC_LINE_CODING_PARITY_NONE = 0, + CDC_LINE_CODING_PARITY_ODD = 1, + CDC_LINE_CODING_PARITY_EVEN = 2, + CDC_LINE_CODING_PARITY_MARK = 3, + CDC_LINE_CODING_PARITY_SPACE = 4, +}; + //--------------------------------------------------------------------+ // Management Element Notification (Notification Endpoint) //--------------------------------------------------------------------+ @@ -207,13 +223,13 @@ typedef enum { CDC_NOTIF_NETWORK_CONNECTION = 0x00, ///< This notification allows the device to notify the host about network connection status. CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request. - CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08, - CDC_NOTIF_RING_DETECT = 0x09, - CDC_NOTIF_SERIAL_STATE = 0x20, - CDC_NOTIF_CALL_STATE_CHANGE = 0x28, - CDC_NOTIF_LINE_STATE_CHANGE = 0x29, + CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08,///< CDC_NOTIF_AUX_JACK_HOOK_STATE + CDC_NOTIF_RING_DETECT = 0x09,///< CDC_NOTIF_RING_DETECT + CDC_NOTIF_SERIAL_STATE = 0x20,///< CDC_NOTIF_SERIAL_STATE + CDC_NOTIF_CALL_STATE_CHANGE = 0x28,///< CDC_NOTIF_CALL_STATE_CHANGE + CDC_NOTIF_LINE_STATE_CHANGE = 0x29,///< CDC_NOTIF_LINE_STATE_CHANGE CDC_NOTIF_CONNECTION_SPEED_CHANGE = 0x2A, ///< This notification allows the device to inform the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred - CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40, + CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40,///< CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION }cdc_notification_request_t; //--------------------------------------------------------------------+ diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index de1466cb18..fcabb922a6 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -52,8 +52,8 @@ typedef struct { cdc_acm_capability_t acm_capability; uint8_t ep_notif; - // Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) - uint8_t line_state; + cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width + uint8_t line_state; // DTR (bit0), RTS (bit1) tuh_xfer_cb_t user_control_cb; @@ -240,6 +240,13 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); break; + case CDC_REQUEST_SET_LINE_CODING: + { + uint16_t const len = tu_min16(sizeof(cdc_line_coding_t), tu_le16toh(xfer->setup->wLength)); + memcpy(&p_cdc->line_coding, xfer->buffer, len); + } + break; + default: break; } } @@ -265,7 +272,7 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c }, .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, .wValue = tu_htole16(line_state), - .wIndex = tu_htole16(p_cdc->bInterfaceNumber), + .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), .wLength = 0 }; @@ -283,6 +290,46 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c return tuh_control_xfer(&xfer); } +bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc && p_cdc->acm_capability.support_line_request); + + TU_LOG_CDCH("CDC Set Line Conding\r\n"); + + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = CDC_REQUEST_SET_LINE_CODING, + .wValue = 0, + .wIndex = tu_htole16(p_cdc->bInterfaceNumber), + .wLength = tu_htole16(sizeof(cdc_line_coding_t)) + }; + + // use usbh enum buf to hold line coding since user line_coding variable may not live long enough + // for the transfer to complete + uint8_t* enum_buf = usbh_get_enum_buf(); + memcpy(enum_buf, line_coding, sizeof(cdc_line_coding_t)); + + p_cdc->user_control_cb = complete_cb; + tuh_xfer_t xfer = + { + .daddr = p_cdc->daddr, + .ep_addr = 0, + .setup = &request, + .buffer = enum_buf, + .complete_cb = cdch_internal_control_complete, + .user_data = user_data + }; + + return tuh_control_xfer(&xfer); +} + //--------------------------------------------------------------------+ // CLASS-USBH API //--------------------------------------------------------------------+ @@ -448,46 +495,70 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d return true; } -static void config_cdc_complete(uint8_t daddr, uint8_t itf_num) +enum { - uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); + CONFIG_SET_CONTROL_LINE_STATE, + CONFIG_SET_LINE_CODING, + CONFIG_COMPLETE +}; - if (idx != TUSB_INDEX_INVALID) +static void process_cdc_config(tuh_xfer_t* xfer) +{ + uintptr_t const state = xfer->user_data; + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + TU_ASSERT(idx != TUSB_INDEX_INVALID, ); + + switch(state) { - if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); + case CONFIG_SET_CONTROL_LINE_STATE: + #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + TU_ASSERT( tuh_cdc_set_control_line_state(idx, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, process_cdc_config, CONFIG_SET_LINE_CODING), ); + break; + #endif + TU_ATTR_FALLTHROUGH; - // Prepare for incoming data - cdch_interface_t* p_cdc = get_itf(idx); - tu_edpt_stream_read_xfer(&p_cdc->stream.rx); - } + case CONFIG_SET_LINE_CODING: + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + { + cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT( tuh_cdc_set_line_coding(idx, &line_coding, process_cdc_config, 0), ); + break; + } + #endif + TU_ATTR_FALLTHROUGH; - // notify usbh that driver enumeration is complete - // itf_num+1 to account for data interface as well - usbh_driver_set_config_complete(daddr, itf_num+1); -} + case CONFIG_COMPLETE: + if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); -#if CFG_TUH_CDC_SET_DTRRTS_ON_ENUM + // Prepare for incoming data + cdch_interface_t* p_cdc = get_itf(idx); + tu_edpt_stream_read_xfer(&p_cdc->stream.rx); -static void config_set_dtr_rts_complete (tuh_xfer_t* xfer) -{ - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - config_cdc_complete(xfer->daddr, itf_num); + // notify usbh that driver enumeration is complete + // itf_num+1 to account for data interface as well + usbh_driver_set_config_complete(xfer->daddr, itf_num+1); + break; + + default: break; + } } bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { - uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); - return tuh_cdc_set_control_line_state(idx, CFG_TUH_CDC_SET_DTRRTS_ON_ENUM, config_set_dtr_rts_complete, 0); -} + // fake transfer to kick-off process + tusb_control_request_t request; + request.wIndex = tu_htole16((uint16_t) itf_num); -#else + tuh_xfer_t xfer; + xfer.daddr = daddr; + xfer.result = XFER_RESULT_SUCCESS; + xfer.setup = &request; + xfer.user_data = CONFIG_SET_CONTROL_LINE_STATE; + + process_cdc_config(&xfer); -bool cdch_set_config(uint8_t daddr, uint8_t itf_num) -{ - config_cdc_complete(daddr, itf_num); return true; } #endif - -#endif diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 5407c646d8..9bf5af46ca 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -37,11 +37,16 @@ // Class Driver Configuration //--------------------------------------------------------------------+ -// Set DTR ( bit 0), RTS (bit 1) on enumeration/mounted -#ifndef CFG_TUH_CDC_SET_DTRRTS_ON_ENUM -#define CFG_TUH_CDC_SET_DTRRTS_ON_ENUM 0 +// Set Line Control state on enumeration/mounted: DTR ( bit 0), RTS (bit 1) +#ifndef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM +#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0 #endif +// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t +//#ifndef CFG_TUH_CDC_LINE_CODING_ON_ENUM +//#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } +//#endif + // RX FIFO size #ifndef CFG_TUH_CDC_RX_BUFSIZE #define CFG_TUH_CDC_RX_BUFSIZE USBH_EPSIZE_BULK_MAX @@ -130,9 +135,12 @@ bool tuh_cdc_read_clear (uint8_t idx); // Control Endpoint (Request) API //--------------------------------------------------------------------+ -// Send control request to Set Control Line State: DTR (bit 0), RTS (bit 1) +// Request to Set Control Line State: DTR (bit 0), RTS (bit 1) bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +// Request to Set Line Coding +bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + // Connect by set both DTR, RTS static inline bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { From 14d45b580e0cd82e77e36ecb152f7c001d860ce7 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 22 Dec 2022 19:17:09 +0700 Subject: [PATCH 26/28] correct host cdc enum --- src/class/cdc/cdc_host.c | 2 +- src/host/usbh.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index fcabb922a6..05e0bdfc73 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -522,7 +522,7 @@ static void process_cdc_config(tuh_xfer_t* xfer) #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM { cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT( tuh_cdc_set_line_coding(idx, &line_coding, process_cdc_config, 0), ); + TU_ASSERT( tuh_cdc_set_line_coding(idx, &line_coding, process_cdc_config, CONFIG_COMPLETE), ); break; } #endif diff --git a/src/host/usbh.c b/src/host/usbh.c index f0ca7be2ed..af1e67d4d1 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -330,6 +330,8 @@ bool tuh_init(uint8_t controller_id) TU_LOG_INT(USBH_DEBUG, sizeof(hcd_event_t)); TU_LOG_INT(USBH_DEBUG, sizeof(_ctrl_xfer)); TU_LOG_INT(USBH_DEBUG, sizeof(tuh_xfer_t)); + TU_LOG_INT(USBH_DEBUG, sizeof(tu_fifo_t)); + TU_LOG_INT(USBH_DEBUG, sizeof(tu_edpt_stream_t)); // Event queue _usbh_q = osal_queue_create( &_usbh_qdef ); @@ -1275,7 +1277,7 @@ static void process_enumeration(tuh_xfer_t* xfer) break; } #endif - __attribute__((fallthrough)); + TU_ATTR_FALLTHROUGH; #endif case ENUM_SET_ADDR: From f33883c308959aa2ca08ef55282c82c54f929226 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 22 Dec 2022 19:41:39 +0700 Subject: [PATCH 27/28] add tuh_cdc_get_local_line_coding() --- examples/host/cdc_msc_hid/src/cdc_app.c | 15 +++++++++++++-- src/class/cdc/cdc_host.c | 22 ++++++++++++++++++++-- src/class/cdc/cdc_host.h | 12 ++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index dd3196146e..b1b137e0e0 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -90,7 +90,18 @@ void tuh_cdc_mount_cb(uint8_t idx) tuh_cdc_itf_info_t itf_info = { 0 }; tuh_cdc_itf_get_info(idx, &itf_info); - printf("CDC Interface is mounted: device address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.bInterfaceNumber); + printf("CDC Interface is mounted: address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.bInterfaceNumber); + +#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + // CFG_TUH_CDC_LINE_CODING_ON_ENUM must be defined for line coding is set by tinyusb in enumeration + // otherwise you need to call tuh_cdc_set_line_coding() first + cdc_line_coding_t line_coding = { 0 }; + if ( tuh_cdc_get_local_line_coding(idx, &line_coding) ) + { + printf(" Baudrate: %lu, Stop Bits : %u\r\n", line_coding.bit_rate, line_coding.stop_bits); + printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity , line_coding.data_bits); + } +#endif } void tuh_cdc_umount_cb(uint8_t idx) @@ -98,5 +109,5 @@ void tuh_cdc_umount_cb(uint8_t idx) tuh_cdc_itf_info_t itf_info = { 0 }; tuh_cdc_itf_get_info(idx, &itf_info); - printf("CDC Interface is unmounted: device address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.bInterfaceNumber); + printf("CDC Interface is unmounted: address = %u, itf_num = %u\r\n", itf_info.daddr, itf_info.bInterfaceNumber); } diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 05e0bdfc73..17dc877f80 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -52,8 +52,8 @@ typedef struct { cdc_acm_capability_t acm_capability; uint8_t ep_notif; - cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width - uint8_t line_state; // DTR (bit0), RTS (bit1) + cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width + uint8_t line_state; // DTR (bit0), RTS (bit1) tuh_xfer_cb_t user_control_cb; @@ -162,6 +162,20 @@ bool tuh_cdc_get_rts(uint8_t idx) return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS) ? true : false; } +bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + *line_coding = p_cdc->line_coding; + + return true; +} + +//--------------------------------------------------------------------+ +// Write +//--------------------------------------------------------------------+ + uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) { cdch_interface_t* p_cdc = get_itf(idx); @@ -194,6 +208,10 @@ uint32_t tuh_cdc_write_available(uint8_t idx) return tu_edpt_stream_write_available(&p_cdc->stream.tx); } +//--------------------------------------------------------------------+ +// Read +//--------------------------------------------------------------------+ + uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) { cdch_interface_t* p_cdc = get_itf(idx); diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 9bf5af46ca..502ad430db 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -102,6 +102,12 @@ TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) return tuh_cdc_get_dtr(idx); } +// Get local (saved/cached) version of line coding. +// This function should return correct values if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding() +// are invoked previously or CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined. +// NOTE: This function does not make any USB transfer request to device. +bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding); + //--------------------------------------------------------------------+ // Write API //--------------------------------------------------------------------+ @@ -133,6 +139,7 @@ bool tuh_cdc_read_clear (uint8_t idx); //--------------------------------------------------------------------+ // Control Endpoint (Request) API +// Each Function will make a USB transfer request to/from device //--------------------------------------------------------------------+ // Request to Set Control Line State: DTR (bit 0), RTS (bit 1) @@ -141,6 +148,11 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c // Request to Set Line Coding bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +// Request to Get Line Coding +// Should only use if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding() never got invoked and +// CFG_TUH_CDC_LINE_CODING_ON_ENUM is not defined +// bool tuh_cdc_get_line_coding(uint8_t idx, cdc_line_coding_t* coding); + // Connect by set both DTR, RTS static inline bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { From 396716cc2c29b151556d554c560307afcadd7252 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 22 Dec 2022 20:26:32 +0700 Subject: [PATCH 28/28] clean up --- examples/host/cdc_msc_hid/CMakeLists.txt | 2 +- src/class/cdc/cdc.h | 22 ++++++---------------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/examples/host/cdc_msc_hid/CMakeLists.txt b/examples/host/cdc_msc_hid/CMakeLists.txt index 2e89817a56..7af6b738e8 100644 --- a/examples/host/cdc_msc_hid/CMakeLists.txt +++ b/examples/host/cdc_msc_hid/CMakeLists.txt @@ -15,8 +15,8 @@ add_executable(${PROJECT}) # Example source target_sources(${PROJECT} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/cdc_app.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c ${CMAKE_CURRENT_SOURCE_DIR}/src/hid_app.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_app.c ) diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index 9a3fc21ee5..2fecde3cae 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -41,16 +41,6 @@ /** \defgroup ClassDriver_CDC_Common Common Definitions * @{ */ -// TODO remove -/// CDC Pipe ID, used to indicate which pipe the API is addressing to (Notification, Out, In) -typedef enum -{ - CDC_PIPE_NOTIFICATION , ///< Notification pipe - CDC_PIPE_DATA_IN , ///< Data in pipe - CDC_PIPE_DATA_OUT , ///< Data out pipe - CDC_PIPE_ERROR , ///< Invalid Pipe ID -}cdc_pipeid_t; - //--------------------------------------------------------------------+ // CDC Communication Interface Class //--------------------------------------------------------------------+ @@ -223,13 +213,13 @@ typedef enum { CDC_NOTIF_NETWORK_CONNECTION = 0x00, ///< This notification allows the device to notify the host about network connection status. CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request. - CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08,///< CDC_NOTIF_AUX_JACK_HOOK_STATE - CDC_NOTIF_RING_DETECT = 0x09,///< CDC_NOTIF_RING_DETECT - CDC_NOTIF_SERIAL_STATE = 0x20,///< CDC_NOTIF_SERIAL_STATE - CDC_NOTIF_CALL_STATE_CHANGE = 0x28,///< CDC_NOTIF_CALL_STATE_CHANGE - CDC_NOTIF_LINE_STATE_CHANGE = 0x29,///< CDC_NOTIF_LINE_STATE_CHANGE + CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08, + CDC_NOTIF_RING_DETECT = 0x09, + CDC_NOTIF_SERIAL_STATE = 0x20, + CDC_NOTIF_CALL_STATE_CHANGE = 0x28, + CDC_NOTIF_LINE_STATE_CHANGE = 0x29, CDC_NOTIF_CONNECTION_SPEED_CHANGE = 0x2A, ///< This notification allows the device to inform the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred - CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40,///< CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION + CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40, }cdc_notification_request_t; //--------------------------------------------------------------------+