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
This commit is contained in:
hathach 2022-12-21 00:26:46 +07:00
parent 7004914d8c
commit 854e5222ae
3 changed files with 423 additions and 145 deletions

View File

@ -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
//--------------------------------------------------------------------+

View File

@ -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; i<CFG_TUH_CDC; i++)
TU_ASSERT(idx < CFG_TUH_CDC, NULL);
cdch_interface_t* p_cdc = &cdch_data[idx];
return (p_cdc->daddr != 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; i<CFG_TUH_CDC; i++)
{
if (cdch_data[i].daddr == dev_addr) return &cdch_data[i];
cdch_interface_t* p_cdc = &cdch_data[i];
if ( (p_cdc->daddr == 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; i<CFG_TUH_CDC; i++)
for(uint8_t i=0; i<CFG_TUH_CDC; i++)
{
if (cdch_data[i].daddr == 0) return &cdch_data[i];
}
@ -113,58 +232,119 @@ static cdch_interface_t* find_new_itf(void)
}
//--------------------------------------------------------------------+
// APPLICATION API (parameter validation needed)
// APPLICATION API
//--------------------------------------------------------------------+
bool tuh_cdc_mounted(uint8_t dev_addr)
uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num)
{
cdch_interface_t* p_cdc = get_itf(dev_addr);
for(uint8_t i=0; i<CFG_TUH_CDC; i++)
{
const cdch_interface_t* p_cdc = &cdch_data[i];
if (p_cdc->daddr == 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);
uint8_t const ep_out = cdch_data[dev_addr-1].ep_out;
if ( usbh_edpt_busy(dev_addr, ep_out) ) return false;
return usbh_edpt_xfer(dev_addr, ep_out, (void*)(uintptr_t) p_data, (uint16_t) length);
return tu_edpt_stream_write(p_cdc->daddr, &p_cdc->stream.tx, buffer, bufsize);
}
bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify)
uint32_t tuh_cdc_write_flush(uint8_t idx)
{
(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 usbh_edpt_xfer(dev_addr, ep_in, p_buffer, (uint16_t) length);
return tud_edpt_stream_write_flush(p_cdc->daddr, &p_cdc->stream.tx);
}
bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb)
uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize)
{
cdch_interface_t const * p_cdc = get_itf(dev_addr);
cdch_interface_t* p_cdc = get_itf(idx);
TU_VERIFY(p_cdc);
return tu_edpt_stream_read(p_cdc->daddr, &p_cdc->stream.rx, buffer, bufsize);
}
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);
}
//--------------------------------------------------------------------+
// Control Endpoint API
//--------------------------------------------------------------------+
// internal control complete to update state such as line state, encoding
static void cdch_internal_control_complete(tuh_xfer_t* xfer)
{
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; i<CFG_TUH_CDC; i++)
// {
// cdch_interface_t* p_cdc = &cdch_data[i];
//
//
// }
for(size_t i=0; i<CFG_TUH_CDC; i++)
{
cdch_interface_t* p_cdc = &cdch_data[i];
tu_edpt_stream_init(&p_cdc->stream.tx, true, false,
p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE,
p_cdc->stream.tx_ep_buf, CFG_TUH_CDC_TX_EPSIZE);
tu_edpt_stream_init(&p_cdc->stream.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; idx<CFG_TUH_CDC; idx++)
{
tuh_cdc_umount_cb(dev_addr);
cdch_interface_t* p_cdc = &cdch_data[idx];
if (p_cdc->daddr == 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);
}
}
}
bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t 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);
}
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)
{
(void) ep_addr;
tuh_cdc_xfer_isr( dev_addr, event, 0, xferred_bytes );
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

View File

@ -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;
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 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);
// 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
/// @}