From 4f0369508450883504e377b40aaec8860c8cb256 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 14 Dec 2022 16:52:28 +0700 Subject: adding tuh_cdc_mount_cb/tuh_cdc_umount_cb start adding cdc_app.c to example --- src/class/cdc/cdc_host.h | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'src/class/cdc/cdc_host.h') diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 33dbd2efb..c3b601b34 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); -- cgit v1.3.1 From f62f97395626f316f1670f1777a0a75877e8e773 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 14 Dec 2022 23:19:47 +0700 Subject: 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(-) (limited to 'src/class/cdc/cdc_host.h') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 83fa1bf5e..9678b756c 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 c3b601b34..ce1f0f309 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 ca745464c..504ddca1e 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 9ca6c794b..69972c630 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 //--------------------------------------------------------------------+ -- cgit v1.3.1 From bd1f7f86ce1b6e82c3942d545e984b74b050004e Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 15 Dec 2022 15:27:39 +0700 Subject: 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(-) (limited to 'src/class/cdc/cdc_host.h') diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index fbc7162a3..f625a7554 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 9678b756c..da8ad726b 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 ce1f0f309..b2e75902d 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 1bfa7c7d1..c4c9d4133 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 c156afea0..7f72560c3 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 //--------------------------------------------------------------------+ -- cgit v1.3.1 From 854e5222aea570a2be2201d8c460f54b87c9108a Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 00:26:46 +0700 Subject: 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(-) (limited to 'src/class/cdc/cdc_host.h') diff --git a/examples/host/cdc_msc_hid/src/main.c b/examples/host/cdc_msc_hid/src/main.c index 465e457f7..b34810252 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 482ccf4be..bdfbe3e74 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 b2e75902d..54e082e7d 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 /// @} -- cgit v1.3.1 From 84a483f5ea7446a5cc1a9fe957379dd1f0a6fd4c Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 12:47:00 +0700 Subject: 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(-) (limited to 'src/class/cdc/cdc_host.h') diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index db652efde..23ea05b2b 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 326567689..ba2e9e1b7 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 54e082e7d..dd8ae80ce 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 -- cgit v1.3.1 From cd9008e5a9c8da81d9736f7e0bf72c5ba409a7f1 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 13:05:45 +0700 Subject: 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(-) (limited to 'src/class/cdc/cdc_host.h') diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index 23ea05b2b..dd3196146 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 ba2e9e1b7..ce0efe6e3 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 dd8ae80ce..476431cc5 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 //--------------------------------------------------------------------+ -- cgit v1.3.1 From 9e8ea44925e80abd7189ed7a673762527ee3adfd Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 21 Dec 2022 17:46:11 +0700 Subject: 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(-) (limited to 'src/class/cdc/cdc_host.h') diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index ce0efe6e3..2f3406378 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 476431cc5..02ae69111 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 -- cgit v1.3.1 From 11233e4d3e04ceab1ad6e33d37a166aa48c436de Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 22 Dec 2022 11:43:57 +0700 Subject: 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(-) (limited to 'src/class/cdc/cdc_host.h') diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index c515405cb..e3d9356f6 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 02ae69111..5407c646d 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 //--------------------------------------------------------------------+ -- cgit v1.3.1 From 05c119ce975668eff814c78d5306589fc2d24530 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 22 Dec 2022 18:28:06 +0700 Subject: 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(-) (limited to 'src/class/cdc/cdc_host.h') diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index e3d9356f6..139a921d1 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 6a9669cf2..9a3fc21ee 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 de1466cb1..fcabb922a 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 5407c646d..9bf5af46c 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) { -- cgit v1.3.1 From f33883c308959aa2ca08ef55282c82c54f929226 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 22 Dec 2022 19:41:39 +0700 Subject: 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(-) (limited to 'src/class/cdc/cdc_host.h') diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index dd3196146..b1b137e0e 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 05e0bdfc7..17dc877f8 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 9bf5af46c..502ad430d 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) { -- cgit v1.3.1 From 48d4a67ec5468f9fd7c073acd599a1271b9e877f Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 24 Dec 2022 01:11:13 +0700 Subject: add tuh_cdc_peek() --- src/class/cdc/cdc_device.h | 2 +- src/class/cdc/cdc_host.c | 8 ++++++++ src/class/cdc/cdc_host.h | 3 +++ src/common/tusb_fifo.c | 2 -- src/common/tusb_private.h | 5 +++++ 5 files changed, 17 insertions(+), 3 deletions(-) (limited to 'src/class/cdc/cdc_host.h') diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index a7d25bd32..f8a004df4 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -80,7 +80,7 @@ int32_t tud_cdc_n_read_char (uint8_t itf); // Clear the received FIFO void tud_cdc_n_read_flush (uint8_t itf); -// Get a byte from FIFO at the specified position without removing it +// Get a byte from FIFO without removing it bool tud_cdc_n_peek (uint8_t itf, uint8_t* ui8); // Write bytes to TX FIFO, data may remain in the FIFO for a while diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 17dc877f8..e9c3d34cb 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -228,6 +228,14 @@ uint32_t tuh_cdc_read_available(uint8_t idx) return tu_edpt_stream_read_available(&p_cdc->stream.rx); } +bool tuh_cdc_peek(uint8_t idx, uint8_t* ch) +{ + cdch_interface_t* p_cdc = get_itf(idx); + TU_VERIFY(p_cdc); + + return tu_edpt_stream_peek(&p_cdc->stream.rx, ch); +} + bool tuh_cdc_read_clear (uint8_t idx) { 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 502ad430d..c759527e6 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -134,6 +134,9 @@ 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); +// Get a byte from RX FIFO without removing it +bool tuh_cdc_peek(uint8_t idx, uint8_t* ch); + // Clear the received FIFO bool tuh_cdc_read_clear (uint8_t idx); diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index b857c6444..d45ca09ed 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -682,8 +682,6 @@ uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t* f, void * buffer, uint1 @param[in] f Pointer to the FIFO buffer to manipulate - @param[in] offset - Position to read from in the FIFO buffer with respect to read pointer @param[in] p_buffer Pointer to the place holder for data read from the buffer diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index d0c7a84fb..d5541856c 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -160,6 +160,11 @@ uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t* s) return (uint32_t) tu_fifo_count(&s->ff); } +TU_ATTR_ALWAYS_INLINE static inline +bool tu_edpt_stream_peek(tu_edpt_stream_t* s, uint8_t* ch) +{ + return tu_fifo_peek(&s->ff, ch); +} #ifdef __cplusplus } -- cgit v1.3.1