summaryrefslogtreecommitdiff
path: root/src/class/cdc
diff options
context:
space:
mode:
authorHiFiPhile <[email protected]>2024-10-30 19:36:05 +0100
committerHiFiPhile <[email protected]>2024-10-30 19:47:03 +0100
commit85ff529a310b7e6ec2e4234e3e292fef6432882b (patch)
tree41218fce4db7c23df1073dfdd42fb017c3cf0158 /src/class/cdc
parent418b8b2f133d695362c735f271c966af10b5d251 (diff)
parent8b1e40c3e2447de5b4a86bbcdcc0344946a4793d (diff)
Merge branch 'master' into dcd_notif
Signed-off-by: HiFiPhile <[email protected]>
Diffstat (limited to 'src/class/cdc')
-rw-r--r--src/class/cdc/cdc_device.c247
-rw-r--r--src/class/cdc/cdc_device.h198
-rw-r--r--src/class/cdc/cdc_host.c22
3 files changed, 197 insertions, 270 deletions
diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c
index 5057805e2..6d4aae1f2 100644
--- a/src/class/cdc/cdc_device.c
+++ b/src/class/cdc/cdc_device.c
@@ -45,8 +45,7 @@
//--------------------------------------------------------------------+
#define BULK_PACKET_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
-typedef struct
-{
+typedef struct {
uint8_t rhport;
uint8_t itf_num;
uint8_t ep_notif;
@@ -57,7 +56,7 @@ typedef struct
uint8_t line_state;
/*------------- From this point, data is not cleared by bus reset -------------*/
- char wanted_char;
+ char wanted_char;
TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding;
// FIFO
@@ -74,18 +73,21 @@ typedef struct
CFG_TUSB_MEM_ALIGN cdc_notif_serial_state_t serial_state_buf;
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EP_BUFSIZE];
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CDC_EP_BUFSIZE];
-
-}cdcd_interface_t;
+} cdcd_interface_t;
#define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, wanted_char)
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
-CFG_TUD_MEM_SECTION tu_static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
+CFG_TUD_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
+static tud_cdc_configure_fifo_t _cdcd_fifo_cfg;
+
+static bool _prep_out_transaction (cdcd_interface_t* p_cdc) {
+
+ // Skip if usb is not ready yet
+ TU_VERIFY(tud_ready() && p_cdc->ep_out);
-static bool _prep_out_transaction (cdcd_interface_t* p_cdc)
-{
uint16_t available = tu_fifo_remaining(&p_cdc->rx_ff);
// Prepare for incoming data but only allow what we can store in the ring buffer.
@@ -100,14 +102,11 @@ static bool _prep_out_transaction (cdcd_interface_t* p_cdc)
// fifo can be changed before endpoint is claimed
available = tu_fifo_remaining(&p_cdc->rx_ff);
- if ( available >= sizeof(p_cdc->epout_buf) )
- {
+ if ( available >= sizeof(p_cdc->epout_buf) ) {
return usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_out, p_cdc->epout_buf, sizeof(p_cdc->epout_buf));
- }else
- {
+ }else {
// Release endpoint since we don't make any transfer
usbd_edpt_release(p_cdc->rhport, p_cdc->ep_out);
-
return false;
}
}
@@ -115,28 +114,35 @@ static bool _prep_out_transaction (cdcd_interface_t* p_cdc)
//--------------------------------------------------------------------+
// APPLICATION API
//--------------------------------------------------------------------+
-bool tud_cdc_n_connected(uint8_t itf)
-{
+
+bool tud_cdc_configure_fifo(tud_cdc_configure_fifo_t const* cfg) {
+ TU_VERIFY(cfg);
+ _cdcd_fifo_cfg = (*cfg);
+ return true;
+}
+
+bool tud_cdc_n_ready(uint8_t itf) {
+ return tud_ready() && _cdcd_itf[itf].ep_in != 0 && _cdcd_itf[itf].ep_out != 0;
+}
+
+bool tud_cdc_n_connected(uint8_t itf) {
// DTR (bit 0) active is considered as connected
return tud_ready() && tu_bit_test(_cdcd_itf[itf].line_state, 0);
}
-uint8_t tud_cdc_n_get_line_state (uint8_t itf)
-{
+uint8_t tud_cdc_n_get_line_state(uint8_t itf) {
return _cdcd_itf[itf].line_state;
}
-void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding)
-{
+void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding) {
(*coding) = _cdcd_itf[itf].line_coding;
}
-bool tud_cdc_n_send_uart_state (uint8_t itf, cdc_uart_state_t state)
-{
+bool tud_cdc_n_send_uart_state (uint8_t itf, cdc_uart_state_t state) {
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
// Skip if usb is not ready yet
- TU_VERIFY( tud_ready(), 0 );
+ TU_VERIFY(tud_ready(), 0);
// claim endpoint
TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_notif));
@@ -152,34 +158,29 @@ bool tud_cdc_n_send_uart_state (uint8_t itf, cdc_uart_state_t state)
return usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_notif, (uint8_t *)&p_cdc->serial_state_buf, sizeof(p_cdc->serial_state_buf));
}
-void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted)
-{
+void tud_cdc_n_set_wanted_char(uint8_t itf, char wanted) {
_cdcd_itf[itf].wanted_char = wanted;
}
//--------------------------------------------------------------------+
// READ API
//--------------------------------------------------------------------+
-uint32_t tud_cdc_n_available(uint8_t itf)
-{
+uint32_t tud_cdc_n_available(uint8_t itf) {
return tu_fifo_count(&_cdcd_itf[itf].rx_ff);
}
-uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize)
-{
+uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize) {
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX));
_prep_out_transaction(p_cdc);
return num_read;
}
-bool tud_cdc_n_peek(uint8_t itf, uint8_t* chr)
-{
+bool tud_cdc_n_peek(uint8_t itf, uint8_t* chr) {
return tu_fifo_peek(&_cdcd_itf[itf].rx_ff, chr);
}
-void tud_cdc_n_read_flush (uint8_t itf)
-{
+void tud_cdc_n_read_flush(uint8_t itf) {
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
tu_fifo_clear(&p_cdc->rx_ff);
_prep_out_transaction(p_cdc);
@@ -188,16 +189,15 @@ void tud_cdc_n_read_flush (uint8_t itf)
//--------------------------------------------------------------------+
// WRITE API
//--------------------------------------------------------------------+
-uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize)
-{
+uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) {
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX));
// flush if queue more than packet size
- if ( tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE
- #if CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE
- || tu_fifo_full(&p_cdc->tx_ff) // check full if fifo size is less than packet size
- #endif
+ if (tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE
+ #if CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE
+ || tu_fifo_full(&p_cdc->tx_ff) // check full if fifo size is less than packet size
+ #endif
) {
tud_cdc_n_write_flush(itf);
}
@@ -205,28 +205,25 @@ uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize)
return ret;
}
-uint32_t tud_cdc_n_write_flush (uint8_t itf)
-{
+uint32_t tud_cdc_n_write_flush(uint8_t itf) {
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
// Skip if usb is not ready yet
- TU_VERIFY( tud_ready(), 0 );
+ TU_VERIFY(tud_ready(), 0);
// No data to send
- if ( !tu_fifo_count(&p_cdc->tx_ff) ) return 0;
+ if (!tu_fifo_count(&p_cdc->tx_ff)) return 0;
// Claim the endpoint
- TU_VERIFY( usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_in), 0 );
+ TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_in), 0);
// Pull data from FIFO
uint16_t const count = tu_fifo_read_n(&p_cdc->tx_ff, p_cdc->epin_buf, sizeof(p_cdc->epin_buf));
- if ( count )
- {
- TU_ASSERT( usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 );
+ if (count) {
+ TU_ASSERT(usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0);
return count;
- }else
- {
+ } else {
// Release endpoint since we don't make any transfer
// Note: data is dropped if terminal is not connected
usbd_edpt_release(p_cdc->rhport, p_cdc->ep_in);
@@ -234,33 +231,30 @@ uint32_t tud_cdc_n_write_flush (uint8_t itf)
}
}
-uint32_t tud_cdc_n_write_available (uint8_t itf)
-{
+uint32_t tud_cdc_n_write_available(uint8_t itf) {
return tu_fifo_remaining(&_cdcd_itf[itf].tx_ff);
}
-bool tud_cdc_n_write_clear (uint8_t itf)
-{
+bool tud_cdc_n_write_clear(uint8_t itf) {
return tu_fifo_clear(&_cdcd_itf[itf].tx_ff);
}
//--------------------------------------------------------------------+
// USBD Driver API
//--------------------------------------------------------------------+
-void cdcd_init(void)
-{
+void cdcd_init(void) {
tu_memclr(_cdcd_itf, sizeof(_cdcd_itf));
+ tu_memclr(&_cdcd_fifo_cfg, sizeof(_cdcd_fifo_cfg));
- for(uint8_t i=0; i<CFG_TUD_CDC; i++)
- {
+ for (uint8_t i = 0; i < CFG_TUD_CDC; i++) {
cdcd_interface_t* p_cdc = &_cdcd_itf[i];
p_cdc->wanted_char = (char) -1;
// default line coding is : stop bit = 1, parity = none, data bits = 8
- p_cdc->line_coding.bit_rate = 115200;
+ p_cdc->line_coding.bit_rate = 115200;
p_cdc->line_coding.stop_bits = 0;
- p_cdc->line_coding.parity = 0;
+ p_cdc->line_coding.parity = 0;
p_cdc->line_coding.data_bits = 8;
// Config RX fifo
@@ -304,33 +298,28 @@ bool cdcd_deinit(void) {
return true;
}
-void cdcd_reset(uint8_t rhport)
-{
+void cdcd_reset(uint8_t rhport) {
(void) rhport;
- for(uint8_t i=0; i<CFG_TUD_CDC; i++)
- {
+ for (uint8_t i = 0; i < CFG_TUD_CDC; i++) {
cdcd_interface_t* p_cdc = &_cdcd_itf[i];
tu_memclr(p_cdc, ITF_MEM_RESET_SIZE);
- tu_fifo_clear(&p_cdc->rx_ff);
- tu_fifo_clear(&p_cdc->tx_ff);
+ if (!_cdcd_fifo_cfg.rx_persistent) tu_fifo_clear(&p_cdc->rx_ff);
+ if (!_cdcd_fifo_cfg.tx_persistent) tu_fifo_clear(&p_cdc->tx_ff);
tu_fifo_set_overwritable(&p_cdc->tx_ff, true);
}
}
-uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
-{
+uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) {
// Only support ACM subclass
TU_VERIFY( TUSB_CLASS_CDC == itf_desc->bInterfaceClass &&
CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass, 0);
// Find available interface
- cdcd_interface_t * p_cdc = NULL;
- for(uint8_t cdc_id=0; cdc_id<CFG_TUD_CDC; cdc_id++)
- {
- if ( _cdcd_itf[cdc_id].ep_in == 0 )
- {
+ cdcd_interface_t* p_cdc = NULL;
+ for (uint8_t cdc_id = 0; cdc_id < CFG_TUD_CDC; cdc_id++) {
+ if (_cdcd_itf[cdc_id].ep_in == 0) {
p_cdc = &_cdcd_itf[cdc_id];
break;
}
@@ -342,39 +331,36 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
p_cdc->itf_num = itf_desc->bInterfaceNumber;
uint16_t drv_len = sizeof(tusb_desc_interface_t);
- uint8_t const * p_desc = tu_desc_next( itf_desc );
+ uint8_t const* p_desc = tu_desc_next(itf_desc);
// Communication Functional Descriptors
- while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len )
- {
+ while (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len) {
drv_len += tu_desc_len(p_desc);
- p_desc = tu_desc_next(p_desc);
+ p_desc = tu_desc_next(p_desc);
}
- if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
- {
+ if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) {
// notification endpoint
- tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
+ tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc;
- TU_ASSERT( usbd_edpt_open(rhport, desc_ep), 0 );
+ TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0);
p_cdc->ep_notif = desc_ep->bEndpointAddress;
drv_len += tu_desc_len(p_desc);
- p_desc = tu_desc_next(p_desc);
+ p_desc = tu_desc_next(p_desc);
}
//------------- Data Interface (if any) -------------//
- if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) &&
- (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
- {
+ if ((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) &&
+ (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const*) p_desc)->bInterfaceClass)) {
// next to endpoint descriptor
drv_len += tu_desc_len(p_desc);
- p_desc = tu_desc_next(p_desc);
+ p_desc = tu_desc_next(p_desc);
// Open endpoint pair
- TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in), 0 );
+ TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in), 0);
- drv_len += 2*sizeof(tusb_desc_endpoint_t);
+ drv_len += 2 * sizeof(tusb_desc_endpoint_t);
}
// Prepare for incoming data
@@ -386,8 +372,7 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
// Invoked when a control transfer occurred on an interface of this class
// Driver response accordingly to the request and the transfer stage (setup/data/ack)
// return false to stall control endpoint (e.g unsupported request)
-bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
-{
+bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) {
// Handle class request only
TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
@@ -395,42 +380,33 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
cdcd_interface_t* p_cdc = _cdcd_itf;
// Identify which interface to use
- for ( ; ; itf++, p_cdc++)
- {
+ for (;; itf++, p_cdc++) {
if (itf >= TU_ARRAY_SIZE(_cdcd_itf)) return false;
- if ( p_cdc->itf_num == request->wIndex ) break;
+ if (p_cdc->itf_num == request->wIndex) break;
}
- switch ( request->bRequest )
- {
+ switch (request->bRequest) {
case CDC_REQUEST_SET_LINE_CODING:
- if (stage == CONTROL_STAGE_SETUP)
- {
+ if (stage == CONTROL_STAGE_SETUP) {
TU_LOG_DRV(" Set Line Coding\r\n");
tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
+ } else if (stage == CONTROL_STAGE_ACK) {
+ if (tud_cdc_line_coding_cb) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding);
}
- else if ( stage == CONTROL_STAGE_ACK)
- {
- if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding);
- }
- break;
+ break;
case CDC_REQUEST_GET_LINE_CODING:
- if (stage == CONTROL_STAGE_SETUP)
- {
+ if (stage == CONTROL_STAGE_SETUP) {
TU_LOG_DRV(" Get Line Coding\r\n");
tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
}
- break;
+ break;
case CDC_REQUEST_SET_CONTROL_LINE_STATE:
- if (stage == CONTROL_STAGE_SETUP)
- {
+ if (stage == CONTROL_STAGE_SETUP) {
tud_control_status(rhport, request);
- }
- else if (stage == CONTROL_STAGE_ACK)
- {
+ } else if (stage == CONTROL_STAGE_ACK) {
// CDC PSTN v1.2 section 6.3.12
// Bit 0: Indicates if DTE is present or not.
// This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR (Data Terminal Ready)
@@ -447,61 +423,54 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
TU_LOG_DRV(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts);
// Invoke callback
- if ( tud_cdc_line_state_cb ) tud_cdc_line_state_cb(itf, dtr, rts);
+ if (tud_cdc_line_state_cb) tud_cdc_line_state_cb(itf, dtr, rts);
}
- break;
+ break;
+
case CDC_REQUEST_SEND_BREAK:
- if (stage == CONTROL_STAGE_SETUP)
- {
+ if (stage == CONTROL_STAGE_SETUP) {
tud_control_status(rhport, request);
- }
- else if (stage == CONTROL_STAGE_ACK)
- {
+ } else if (stage == CONTROL_STAGE_ACK) {
TU_LOG_DRV(" Send Break\r\n");
- if ( tud_cdc_send_break_cb ) tud_cdc_send_break_cb(itf, request->wValue);
+ if (tud_cdc_send_break_cb) tud_cdc_send_break_cb(itf, request->wValue);
}
- break;
+ break;
- default: return false; // stall unsupported request
+ default:
+ return false; // stall unsupported request
}
return true;
}
-bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
-{
+bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
(void) result;
uint8_t itf;
cdcd_interface_t* p_cdc;
// Identify which interface to use
- for (itf = 0; itf < CFG_TUD_CDC; itf++)
- {
+ for (itf = 0; itf < CFG_TUD_CDC; itf++) {
p_cdc = &_cdcd_itf[itf];
- if ( ( ep_addr == p_cdc->ep_out ) || ( ep_addr == p_cdc->ep_in ) || ( ep_addr == p_cdc->ep_notif )) break;
+ if ((ep_addr == p_cdc->ep_out) || (ep_addr == p_cdc->ep_in)|| (ep_addr == p_cdc->ep_notif)) break;
}
TU_ASSERT(itf < CFG_TUD_CDC);
// Received new data
- if ( ep_addr == p_cdc->ep_out )
- {
+ if (ep_addr == p_cdc->ep_out) {
tu_fifo_write_n(&p_cdc->rx_ff, p_cdc->epout_buf, (uint16_t) xferred_bytes);
// Check for wanted char and invoke callback if needed
- if ( tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1) )
- {
- for ( uint32_t i = 0; i < xferred_bytes; i++ )
- {
- if ( (p_cdc->wanted_char == p_cdc->epout_buf[i]) && !tu_fifo_empty(&p_cdc->rx_ff) )
- {
+ if (tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1)) {
+ for (uint32_t i = 0; i < xferred_bytes; i++) {
+ if ((p_cdc->wanted_char == p_cdc->epout_buf[i]) && !tu_fifo_empty(&p_cdc->rx_ff)) {
tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char);
}
}
}
// invoke receive callback (if there is still data)
- if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf);
+ if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff)) tud_cdc_rx_cb(itf);
// prepare for OUT transaction
_prep_out_transaction(p_cdc);
@@ -510,19 +479,15 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
// Data sent to host, we continue to fetch from tx fifo to send.
// Note: This will cause incorrect baudrate set in line coding.
// Though maybe the baudrate is not really important !!!
- if ( ep_addr == p_cdc->ep_in )
- {
+ if (ep_addr == p_cdc->ep_in) {
// invoke transmit callback to possibly refill tx fifo
- if ( tud_cdc_tx_complete_cb ) tud_cdc_tx_complete_cb(itf);
+ if (tud_cdc_tx_complete_cb) tud_cdc_tx_complete_cb(itf);
- if ( 0 == tud_cdc_n_write_flush(itf) )
- {
+ if (0 == tud_cdc_n_write_flush(itf)) {
// If there is no data left, a ZLP should be sent if
// xferred_bytes is multiple of EP Packet size and not zero
- if ( !tu_fifo_count(&p_cdc->tx_ff) && xferred_bytes && (0 == (xferred_bytes & (BULK_PACKET_SIZE-1))) )
- {
- if ( usbd_edpt_claim(rhport, p_cdc->ep_in) )
- {
+ if (!tu_fifo_count(&p_cdc->tx_ff) && xferred_bytes && (0 == (xferred_bytes & (BULK_PACKET_SIZE - 1)))) {
+ if (usbd_edpt_claim(rhport, p_cdc->ep_in)) {
usbd_edpt_xfer(rhport, p_cdc->ep_in, NULL, 0);
}
}
diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h
index 92131f159..be0f31844 100644
--- a/src/class/cdc/cdc_device.h
+++ b/src/class/cdc/cdc_device.h
@@ -24,8 +24,8 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef _TUSB_CDC_DEVICE_H_
-#define _TUSB_CDC_DEVICE_H_
+#ifndef TUSB_CDC_DEVICE_H_
+#define TUSB_CDC_DEVICE_H_
#include "cdc.h"
@@ -45,212 +45,174 @@
extern "C" {
#endif
-/** \addtogroup CDC_Serial Serial
- * @{
- * \defgroup CDC_Serial_Device Device
- * @{ */
+//--------------------------------------------------------------------+
+// Driver Configuration
+//--------------------------------------------------------------------+
+
+typedef struct TU_ATTR_PACKED {
+ uint8_t rx_persistent : 1; // keep rx fifo on bus reset or disconnect
+ uint8_t tx_persistent : 1; // keep tx fifo on bus reset or disconnect
+} tud_cdc_configure_fifo_t;
+
+// Configure CDC FIFOs behavior
+bool tud_cdc_configure_fifo(tud_cdc_configure_fifo_t const* cfg);
//--------------------------------------------------------------------+
-// Application API (Multiple Ports)
-// CFG_TUD_CDC > 1
+// Application API (Multiple Ports) i.e. CFG_TUD_CDC > 1
//--------------------------------------------------------------------+
+// Check if interface is ready
+bool tud_cdc_n_ready(uint8_t itf);
+
// Check if terminal is connected to this port
-bool tud_cdc_n_connected (uint8_t itf);
+bool tud_cdc_n_connected(uint8_t itf);
// Get current line state. Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send)
-uint8_t tud_cdc_n_get_line_state (uint8_t itf);
+uint8_t tud_cdc_n_get_line_state(uint8_t itf);
// Get current line encoding: bit rate, stop bits parity etc ..
-void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding);
+void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding);
// Send UART status notification: DCD, DSR etc ..
-bool tud_cdc_n_send_uart_state (uint8_t itf, cdc_uart_state_t state);
+bool tud_cdc_n_send_uart_state(uint8_t itf, cdc_uart_state_t state);
// Set special character that will trigger tud_cdc_rx_wanted_cb() callback on receiving
-void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted);
+void tud_cdc_n_set_wanted_char(uint8_t itf, char wanted);
// Get the number of bytes available for reading
-uint32_t tud_cdc_n_available (uint8_t itf);
+uint32_t tud_cdc_n_available(uint8_t itf);
// Read received bytes
-uint32_t tud_cdc_n_read (uint8_t itf, void* buffer, uint32_t bufsize);
+uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize);
// Read a byte, return -1 if there is none
-static inline
-int32_t tud_cdc_n_read_char (uint8_t itf);
+TU_ATTR_ALWAYS_INLINE static inline int32_t tud_cdc_n_read_char(uint8_t itf) {
+ uint8_t ch;
+ return tud_cdc_n_read(itf, &ch, 1) ? (int32_t) ch : -1;
+}
// Clear the received FIFO
-void tud_cdc_n_read_flush (uint8_t itf);
+void tud_cdc_n_read_flush(uint8_t itf);
// Get a byte from FIFO without removing it
-bool tud_cdc_n_peek (uint8_t itf, uint8_t* ui8);
+bool tud_cdc_n_peek(uint8_t itf, uint8_t* ui8);
// Write bytes to TX FIFO, data may remain in the FIFO for a while
-uint32_t tud_cdc_n_write (uint8_t itf, void const* buffer, uint32_t bufsize);
+uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize);
// Write a byte
-static inline
-uint32_t tud_cdc_n_write_char (uint8_t itf, char ch);
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_n_write_char(uint8_t itf, char ch) {
+ return tud_cdc_n_write(itf, &ch, 1);
+}
// Write a null-terminated string
-static inline
-uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str);
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_n_write_str(uint8_t itf, char const* str) {
+ return tud_cdc_n_write(itf, str, strlen(str));
+}
// Force sending data if possible, return number of forced bytes
-uint32_t tud_cdc_n_write_flush (uint8_t itf);
+uint32_t tud_cdc_n_write_flush(uint8_t itf);
// Return the number of bytes (characters) available for writing to TX FIFO buffer in a single n_write operation.
-uint32_t tud_cdc_n_write_available (uint8_t itf);
+uint32_t tud_cdc_n_write_available(uint8_t itf);
// Clear the transmit FIFO
-bool tud_cdc_n_write_clear (uint8_t itf);
+bool tud_cdc_n_write_clear(uint8_t itf);
//--------------------------------------------------------------------+
// Application API (Single Port)
//--------------------------------------------------------------------+
-static inline bool tud_cdc_connected (void);
-static inline uint8_t tud_cdc_get_line_state (void);
-static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding);
-static inline bool tud_cdc_send_uart_state (cdc_uart_state_t state);
-static inline void tud_cdc_set_wanted_char (char wanted);
-
-static inline uint32_t tud_cdc_available (void);
-static inline int32_t tud_cdc_read_char (void);
-static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize);
-static inline void tud_cdc_read_flush (void);
-static inline bool tud_cdc_peek (uint8_t* ui8);
-
-static inline uint32_t tud_cdc_write_char (char ch);
-static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize);
-static inline uint32_t tud_cdc_write_str (char const* str);
-static inline uint32_t tud_cdc_write_flush (void);
-static inline uint32_t tud_cdc_write_available (void);
-static inline bool tud_cdc_write_clear (void);
-
-//--------------------------------------------------------------------+
-// Application Callback API (weak is optional)
-//--------------------------------------------------------------------+
-
-// Invoked when received new data
-TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf);
-
-// Invoked when received `wanted_char`
-TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char);
-
-// Invoked when a TX is complete and therefore space becomes available in TX buffer
-TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf);
-
-// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE
-TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts);
-
-// Invoked when line coding is change via SET_LINE_CODING
-TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding);
-
-// Invoked when received send break
-TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms);
-
-//--------------------------------------------------------------------+
-// Inline Functions
-//--------------------------------------------------------------------+
-static inline int32_t tud_cdc_n_read_char (uint8_t itf)
-{
- uint8_t ch;
- return tud_cdc_n_read(itf, &ch, 1) ? (int32_t) ch : -1;
-}
-static inline uint32_t tud_cdc_n_write_char(uint8_t itf, char ch)
-{
- return tud_cdc_n_write(itf, &ch, 1);
+TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_ready(void) {
+ return tud_cdc_n_ready(0);
}
-static inline uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str)
-{
- return tud_cdc_n_write(itf, str, strlen(str));
-}
-
-static inline bool tud_cdc_connected (void)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_connected(void) {
return tud_cdc_n_connected(0);
}
-static inline uint8_t tud_cdc_get_line_state (void)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint8_t tud_cdc_get_line_state(void) {
return tud_cdc_n_get_line_state(0);
}
-static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding)
-{
+TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_get_line_coding(cdc_line_coding_t* coding) {
tud_cdc_n_get_line_coding(0, coding);
}
-static inline bool tud_cdc_send_uart_state (cdc_uart_state_t state)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_send_uart_state(cdc_uart_state_t state) {
return tud_cdc_n_send_uart_state(0, state);
}
-static inline void tud_cdc_set_wanted_char (char wanted)
-{
+
+TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_set_wanted_char(char wanted) {
tud_cdc_n_set_wanted_char(0, wanted);
}
-static inline uint32_t tud_cdc_available (void)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_available(void) {
return tud_cdc_n_available(0);
}
-static inline int32_t tud_cdc_read_char (void)
-{
+TU_ATTR_ALWAYS_INLINE static inline int32_t tud_cdc_read_char(void) {
return tud_cdc_n_read_char(0);
}
-static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_read(void* buffer, uint32_t bufsize) {
return tud_cdc_n_read(0, buffer, bufsize);
}
-static inline void tud_cdc_read_flush (void)
-{
+TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_read_flush(void) {
tud_cdc_n_read_flush(0);
}
-static inline bool tud_cdc_peek (uint8_t* ui8)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_peek(uint8_t* ui8) {
return tud_cdc_n_peek(0, ui8);
}
-static inline uint32_t tud_cdc_write_char (char ch)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write_char(char ch) {
return tud_cdc_n_write_char(0, ch);
}
-static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write(void const* buffer, uint32_t bufsize) {
return tud_cdc_n_write(0, buffer, bufsize);
}
-static inline uint32_t tud_cdc_write_str (char const* str)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write_str(char const* str) {
return tud_cdc_n_write_str(0, str);
}
-static inline uint32_t tud_cdc_write_flush (void)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write_flush(void) {
return tud_cdc_n_write_flush(0);
}
-static inline uint32_t tud_cdc_write_available(void)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write_available(void) {
return tud_cdc_n_write_available(0);
}
-static inline bool tud_cdc_write_clear(void)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_write_clear(void) {
return tud_cdc_n_write_clear(0);
}
-/** @} */
-/** @} */
+//--------------------------------------------------------------------+
+// Application Callback API (weak is optional)
+//--------------------------------------------------------------------+
+
+// Invoked when received new data
+TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf);
+
+// Invoked when received `wanted_char`
+TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char);
+
+// Invoked when a TX is complete and therefore space becomes available in TX buffer
+TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf);
+
+// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE
+TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts);
+
+// Invoked when line coding is change via SET_LINE_CODING
+TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding);
+
+// Invoked when received send break
+TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms);
//--------------------------------------------------------------------+
// INTERNAL USBD-CLASS DRIVER API
diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c
index 133a10f6e..8717970e6 100644
--- a/src/class/cdc/cdc_host.c
+++ b/src/class/cdc/cdc_host.c
@@ -341,14 +341,14 @@ 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->stream.tx, buffer, bufsize);
+ return tu_edpt_stream_write(p_cdc->daddr, &p_cdc->stream.tx, buffer, bufsize);
}
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->stream.tx);
+ return tu_edpt_stream_write_xfer(p_cdc->daddr, &p_cdc->stream.tx);
}
bool tuh_cdc_write_clear(uint8_t idx) {
@@ -362,7 +362,7 @@ 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);
+ return tu_edpt_stream_write_available(p_cdc->daddr, &p_cdc->stream.tx);
}
//--------------------------------------------------------------------+
@@ -373,7 +373,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->stream.rx, buffer, bufsize);
+ return tu_edpt_stream_read(p_cdc->daddr, &p_cdc->stream.rx, buffer, bufsize);
}
uint32_t tuh_cdc_read_available(uint8_t idx) {
@@ -395,7 +395,7 @@ bool tuh_cdc_read_clear (uint8_t idx) {
TU_VERIFY(p_cdc);
bool ret = tu_edpt_stream_clear(&p_cdc->stream.rx);
- tu_edpt_stream_read_xfer(&p_cdc->stream.rx);
+ tu_edpt_stream_read_xfer(p_cdc->daddr, &p_cdc->stream.rx);
return ret;
}
@@ -677,10 +677,10 @@ 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(&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:
// - xferred_bytes is multiple of EP Packet size and not zero
- tu_edpt_stream_write_zlp_if_needed(&p_cdc->stream.tx, xferred_bytes);
+ tu_edpt_stream_write_zlp_if_needed(daddr, &p_cdc->stream.tx, xferred_bytes);
}
} else if ( ep_addr == p_cdc->stream.rx.ep_addr ) {
#if CFG_TUH_CDC_FTDI
@@ -698,7 +698,7 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t
if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(idx);
// prepare for next transfer if needed
- tu_edpt_stream_read_xfer(&p_cdc->stream.rx);
+ tu_edpt_stream_read_xfer(daddr, &p_cdc->stream.rx);
}else if ( ep_addr == p_cdc->ep_notif ) {
// TODO handle notification endpoint
}else {
@@ -719,9 +719,9 @@ static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t co
TU_ASSERT(tuh_edpt_open(p_cdc->daddr, desc_ep));
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
- tu_edpt_stream_open(&p_cdc->stream.rx, p_cdc->daddr, desc_ep);
+ tu_edpt_stream_open(&p_cdc->stream.rx, desc_ep);
} else {
- tu_edpt_stream_open(&p_cdc->stream.tx, p_cdc->daddr, desc_ep);
+ tu_edpt_stream_open(&p_cdc->stream.tx, desc_ep);
}
desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(desc_ep);
@@ -763,7 +763,7 @@ static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t i
if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx);
// Prepare for incoming data
- tu_edpt_stream_read_xfer(&p_cdc->stream.rx);
+ tu_edpt_stream_read_xfer(p_cdc->daddr, &p_cdc->stream.rx);
// notify usbh that driver enumeration is complete
usbh_driver_set_config_complete(p_cdc->daddr, itf_num);