Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cdc: add uart status notification support. #2593

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 10 additions & 1 deletion examples/device/cdc_dual_ports/src/main.c
Expand Up @@ -94,7 +94,6 @@ void tud_umount_cb(void) {
blink_interval_ms = BLINK_NOT_MOUNTED;
}


//--------------------------------------------------------------------+
// USB CDC
//--------------------------------------------------------------------+
Expand All @@ -115,6 +114,16 @@ static void cdc_task(void) {
echo_serial_port(0, buf, count);
echo_serial_port(1, buf, count);
}

// Press on-board button to send Uart status notification
static uint32_t btn_prev = 0;
static cdc_uart_state_t state = {0};
uint32_t btn = board_button_read();
if (!btn_prev && btn) {
state.bTxCarrier ^= 1;
tud_cdc_send_uart_state(state);
}
btn_prev = btn;
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions examples/device/cdc_dual_ports/src/usb_descriptors.c
Expand Up @@ -136,10 +136,10 @@ uint8_t const desc_fs_configuration[] =
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),

// 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 10, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64),

// 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 10, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64),
};

#if TUD_OPT_HIGH_SPEED
Expand All @@ -151,10 +151,10 @@ uint8_t const desc_hs_configuration[] =
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),

// 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 512),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 10, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 512),

// 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 512),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 10, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 512),
};

// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed
Expand Down
29 changes: 29 additions & 0 deletions src/class/cdc/cdc.h
Expand Up @@ -412,6 +412,35 @@ typedef struct TU_ATTR_PACKED

TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct");

//--------------------------------------------------------------------+
// Notifications
//--------------------------------------------------------------------+
typedef struct TU_ATTR_PACKED
{
uint16_t bRxCarrier : 1;
uint16_t bTxCarrier : 1;
uint16_t bBreak : 1;
uint16_t bRingSignal : 1;
uint16_t bFraming : 1;
uint16_t bParity : 1;
uint16_t bOverRun : 1;
uint16_t : 9;
} cdc_uart_state_t;

typedef struct TU_ATTR_PACKED
{
uint8_t bmRequestType;
uint8_t bNotification;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
cdc_uart_state_t bmUartState;
} cdc_notif_serial_state_t;

TU_VERIFY_STATIC(sizeof(cdc_notif_serial_state_t) == 10, "size is not correct");

#define CDC_REQ_TYPE_NOTIF 0xA1 ///< Direction IN; Type Class; Recipient Interface

TU_ATTR_PACKED_END // End of all packed definitions
TU_ATTR_BIT_FIELD_ORDER_END

Expand Down
42 changes: 31 additions & 11 deletions src/class/cdc/cdc_device.c
Expand Up @@ -47,6 +47,7 @@

typedef struct
{
uint8_t rhport;
uint8_t itf_num;
uint8_t ep_notif;
uint8_t ep_in;
Expand All @@ -70,6 +71,7 @@ typedef struct
OSAL_MUTEX_DEF(tx_ff_mutex);

// Endpoint Transfer buffer
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];

Expand All @@ -84,7 +86,6 @@ CFG_TUD_MEM_SECTION tu_static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];

static bool _prep_out_transaction (cdcd_interface_t* p_cdc)
{
uint8_t const rhport = 0;
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.
Expand All @@ -94,18 +95,18 @@ static bool _prep_out_transaction (cdcd_interface_t* p_cdc)
TU_VERIFY(available >= sizeof(p_cdc->epout_buf));

// claim endpoint
TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_out));
TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_out));

// fifo can be changed before endpoint is claimed
available = tu_fifo_remaining(&p_cdc->rx_ff);

if ( available >= sizeof(p_cdc->epout_buf) )
{
return usbd_edpt_xfer(rhport, p_cdc->ep_out, p_cdc->epout_buf, 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
{
// Release endpoint since we don't make any transfer
usbd_edpt_release(rhport, p_cdc->ep_out);
usbd_edpt_release(p_cdc->rhport, p_cdc->ep_out);

return false;
}
Expand All @@ -130,12 +131,32 @@ 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)
{
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];

// Skip if usb is not ready yet
TU_VERIFY( tud_ready(), 0 );

// claim endpoint
TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_notif));

p_cdc->serial_state_buf.bmRequestType = CDC_REQ_TYPE_NOTIF;
p_cdc->serial_state_buf.bNotification = CDC_NOTIF_SERIAL_STATE;
p_cdc->serial_state_buf.wValue = 0;
p_cdc->serial_state_buf.wIndex = p_cdc->itf_num;
p_cdc->serial_state_buf.wLength = 2;
p_cdc->serial_state_buf.bmUartState = state;

// transfer
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)
{
_cdcd_itf[itf].wanted_char = wanted;
}


//--------------------------------------------------------------------+
// READ API
//--------------------------------------------------------------------+
Expand Down Expand Up @@ -194,23 +215,21 @@ uint32_t tud_cdc_n_write_flush (uint8_t itf)
// No data to send
if ( !tu_fifo_count(&p_cdc->tx_ff) ) return 0;

uint8_t const rhport = 0;

// Claim the endpoint
TU_VERIFY( usbd_edpt_claim(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(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 );
TU_ASSERT( usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_in, p_cdc->epin_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);
usbd_edpt_release(p_cdc->rhport, p_cdc->ep_in);
return 0;
}
}
Expand Down Expand Up @@ -319,6 +338,7 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
TU_ASSERT(p_cdc, 0);

//------------- Control Interface -------------//
p_cdc->rhport = rhport;
p_cdc->itf_num = itf_desc->bInterfaceNumber;

uint16_t drv_len = sizeof(tusb_desc_interface_t);
Expand Down Expand Up @@ -459,7 +479,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
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 ) ) 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);

Expand Down
9 changes: 9 additions & 0 deletions src/class/cdc/cdc_device.h
Expand Up @@ -64,6 +64,9 @@ 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);

// Send UART status notification: DCD, DSR etc ..
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);

Expand Down Expand Up @@ -109,6 +112,7 @@ bool tud_cdc_n_write_clear (uint8_t itf);
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);
Expand Down Expand Up @@ -180,6 +184,11 @@ 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)
{
return tud_cdc_n_send_uart_state(0, state);
}

static inline void tud_cdc_set_wanted_char (char wanted)
{
tud_cdc_n_set_wanted_char(0, wanted);
Expand Down