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 Notification Endpoint, so we can send DSR/DCD/RI. #493

Open
wants to merge 6 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/MassStorage/msc_external_flash/.skip.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pico_rp2040_tinyusb_host
CH32V20x_EVT
feather_rp2040_tinyusb
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #500

1 change: 1 addition & 0 deletions examples/MassStorage/msc_external_flash_sdcard/.skip.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pico_rp2040_tinyusb_host
CH32V20x_EVT
feather_rp2040_tinyusb
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #500

1 change: 1 addition & 0 deletions examples/MassStorage/msc_sdfat/.skip.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pico_rp2040_tinyusb_host
feather_rp2040_tinyusb
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #500

40 changes: 39 additions & 1 deletion src/arduino/Adafruit_USBD_CDC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,15 @@
// esp32 use built-in core cdc
#if CFG_TUD_CDC && !defined(ARDUINO_ARCH_ESP32)

// Include before "Arduino.h" because TinyUSB is part of platform cores
// When developing TinyUSB, it needs to include the local version, not the
// platform core version, which is what gets included by Arduino.h
#include "Adafruit_USBD_CDC.h"

#include "Arduino.h"

#include "Adafruit_TinyUSB_API.h"

#include "Adafruit_USBD_CDC.h"
#include "Adafruit_USBD_Device.h"

#ifndef TINYUSB_API_VERSION
Expand Down Expand Up @@ -170,6 +174,40 @@ int Adafruit_USBD_CDC::dtr(void) {
return tud_cdc_n_connected(_instance);
}

bool Adafruit_USBD_CDC::rts(void) {
return tud_cdc_n_get_line_state(_instance) & CDC_CONTROL_LINE_STATE_RTS;
}

bool Adafruit_USBD_CDC::dsr(void) {
return tud_cdc_n_get_serial_state(_instance).dsr;
}

bool Adafruit_USBD_CDC::dcd(void) {
return tud_cdc_n_get_serial_state(_instance).dcd;
}

bool Adafruit_USBD_CDC::ri(void) {
return tud_cdc_n_get_serial_state(_instance).ri;
}

void Adafruit_USBD_CDC::dsr(bool c) {
cdc_serial_state_t serial_state = tud_cdc_n_get_serial_state(_instance);
serial_state.dsr = c;
tud_cdc_n_set_serial_state(_instance, serial_state);
}

void Adafruit_USBD_CDC::dcd(bool c) {
cdc_serial_state_t serial_state = tud_cdc_n_get_serial_state(_instance);
serial_state.dcd = c;
tud_cdc_n_set_serial_state(_instance, serial_state);
}

void Adafruit_USBD_CDC::ri(bool c) {
cdc_serial_state_t serial_state = tud_cdc_n_get_serial_state(_instance);
serial_state.ri = c;
tud_cdc_n_set_serial_state(_instance, serial_state);
}

Adafruit_USBD_CDC::operator bool() {
if (!isValid()) {
return false;
Expand Down
16 changes: 15 additions & 1 deletion src/arduino/Adafruit_USBD_CDC.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,21 @@ class Adafruit_USBD_CDC : public Stream, public Adafruit_USBD_Interface {
uint8_t stopbits(void);
uint8_t paritytype(void);
uint8_t numbits(void);
int dtr(void);

// Flow control bit getters.
int dtr(void); // pre-existing, I don't want to change the return type.
bool rts(void);
// bool cts(void); // NOT PART OF THE CDC ACM SPEC?!
bool dsr(void);
bool dcd(void);
bool ri(void);

// Flow control bit setters.
// void cts(bool c); // NOT PART OF CDC ACM SPEC?!
void dsr(bool c);
void dcd(bool c);
void ri(bool c);
// Break is a little harder, it's an event, not a state.

// Stream API
virtual int available(void);
Expand Down
43 changes: 43 additions & 0 deletions src/class/cdc/cdc.h
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,49 @@ typedef struct TU_ATTR_PACKED

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

//--------------------------------------------------------------------+
// Notifications
//--------------------------------------------------------------------+

typedef union TU_ATTR_PACKED {
struct {
uint16_t dcd :1;
uint16_t dsr :1;
uint16_t break_err :1;
uint16_t ri :1;
uint16_t frame_err :1;
uint16_t parity_err :1;
uint16_t overrun_err :1;
uint16_t :9;
};
uint16_t state;
} cdc_serial_state_t;

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

typedef struct TU_ATTR_PACKED {
tusb_notification_t header;
union {
cdc_serial_state_t serial_state;
// Add more Notification "Data" payloads here as more are implemented.
};
} cdc_notify_struct_t;

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

tu_static const cdc_notify_struct_t cdc_notify_serial_status = {
.header = {
.bmRequestType_bit = {
.recipient = TUSB_REQ_RCPT_INTERFACE,
.type = TUSB_REQ_TYPE_CLASS,
.direction = TUSB_DIR_IN,
},
.bNotification = CDC_NOTIF_SERIAL_STATE,
.wValue = 0,
.wLength = sizeof(cdc_serial_state_t),
}
};

TU_ATTR_PACKED_END // End of all packed definitions
TU_ATTR_BIT_FIELD_ORDER_END

Expand Down
51 changes: 48 additions & 3 deletions src/class/cdc/cdc_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ typedef struct {
// Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send)
uint8_t line_state;

// Notify host of flow control bits: DSR, DCD, RI, and some error flags.
cdc_serial_state_t serial_state;
bool serial_state_changed;

/*------------- From this point, data is not cleared by bus reset -------------*/
char wanted_char;
TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding;
Expand All @@ -76,6 +80,7 @@ typedef struct {
// Endpoint Transfer buffer
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];
CFG_TUSB_MEM_ALIGN cdc_notify_struct_t epnotif_buf;
} cdcd_interface_t;

#define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, wanted_char)
Expand Down Expand Up @@ -115,6 +120,29 @@ static bool _prep_out_transaction (cdcd_interface_t* p_cdc) {
}
}

bool _send_serial_state_notification(cdcd_interface_t *p_cdc) {
const uint8_t rhport = 0;

if (!p_cdc->serial_state_changed) {
// Nothing to do.
return true;
}

if (!usbd_edpt_claim(rhport, p_cdc->ep_notif)) {
// If claim failed, we're already in the middle of a transaction.
// cdcd_xfer_cb() will pick up this change.
return true;
}

// We have the end point. Build and send the notification.
p_cdc->serial_state_changed = false;

p_cdc->epnotif_buf = cdc_notify_serial_status;
p_cdc->epnotif_buf.header.wIndex = p_cdc->itf_num;
p_cdc->epnotif_buf.serial_state = p_cdc->serial_state;
return usbd_edpt_xfer(rhport, p_cdc->ep_notif, (uint8_t *) &(p_cdc->epnotif_buf), sizeof(p_cdc->epnotif_buf));
}

//--------------------------------------------------------------------+
// APPLICATION API
//--------------------------------------------------------------------+
Expand All @@ -138,6 +166,19 @@ uint8_t tud_cdc_n_get_line_state(uint8_t itf) {
return _cdcd_itf[itf].line_state;
}

cdc_serial_state_t tud_cdc_n_get_serial_state(uint8_t itf) {
return _cdcd_itf[itf].serial_state;
}

void tud_cdc_n_set_serial_state(uint8_t itf, cdc_serial_state_t serial_state) {
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
if (p_cdc->serial_state.state != serial_state.state) {
p_cdc->serial_state_changed = true;
p_cdc->serial_state = serial_state;
_send_serial_state_notification(p_cdc);
}
}

void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding) {
(*coding) = _cdcd_itf[itf].line_coding;
}
Expand Down Expand Up @@ -437,10 +478,10 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
// Identify which interface to use
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);

// Received new data
if (ep_addr == p_cdc->ep_out) {
tu_fifo_write_n(&p_cdc->rx_ff, p_cdc->epout_buf, (uint16_t) xferred_bytes);
Expand Down Expand Up @@ -479,7 +520,11 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
}
}

// nothing to do with notif endpoint for now
// Notifications
if (ep_addr == p_cdc->ep_notif) {
// Send any changes that may have come in while sending the previous change.
return _send_serial_state_notification(p_cdc);
}

return true;
}
Expand Down
14 changes: 14 additions & 0 deletions src/class/cdc/cdc_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ 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);

// Get current serial state.
cdc_serial_state_t tud_cdc_n_get_serial_state(uint8_t itf);

// Set current serial state.
void tud_cdc_n_set_serial_state(uint8_t itf, cdc_serial_state_t ser_state);

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

Expand Down Expand Up @@ -132,6 +138,14 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t tud_cdc_get_line_state(void) {
return tud_cdc_n_get_line_state(0);
}

TU_ATTR_ALWAYS_INLINE static inline cdc_serial_state_t tud_cdc_get_serial_state(void) {
return tud_cdc_n_get_serial_state(0);
}

TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_set_serial_state(cdc_serial_state_t ser_state) {
tud_cdc_n_set_serial_state(0, ser_state);
}

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);
}
Expand Down
21 changes: 21 additions & 0 deletions src/common/tusb_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,27 @@ typedef struct TU_ATTR_PACKED {

TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "size is not correct");


typedef struct TU_ATTR_PACKED {
union {
struct TU_ATTR_PACKED {
uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t.
uint8_t type : 2; ///< Request type tusb_request_type_t.
uint8_t direction : 1; ///< Direction type. tusb_dir_t
} bmRequestType_bit;

uint8_t bmRequestType;
};

uint8_t bNotification;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
} tusb_notification_t;

TU_VERIFY_STATIC( sizeof(tusb_notification_t) == 8, "size is not correct");


TU_ATTR_PACKED_END // End of all packed definitions
TU_ATTR_BIT_FIELD_ORDER_END

Expand Down