Skip to content

Commit 7c0cc53

Browse files
committed
Handle Notification Endpoint, can send CTS/DSR/DCD/RI. #491
1 parent c92b7fd commit 7c0cc53

File tree

6 files changed

+185
-6
lines changed

6 files changed

+185
-6
lines changed

src/arduino/Adafruit_USBD_CDC.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,50 @@ int Adafruit_USBD_CDC::dtr(void) {
170170
return tud_cdc_n_connected(_instance);
171171
}
172172

173+
inline bool Adafruit_USBD_CDC::rts(void) {
174+
return tud_cdc_n_get_line_state(_instance) & CDC_CONTROL_LINE_STATE_RTS;
175+
}
176+
177+
inline bool Adafruit_USBD_CDC::cts(void) {
178+
return tud_cdc_n_get_serial_state(_instance).cts;
179+
}
180+
181+
inline bool Adafruit_USBD_CDC::dsr(void) {
182+
return tud_cdc_n_get_serial_state(_instance).dsr;
183+
}
184+
185+
inline bool Adafruit_USBD_CDC::dcd(void) {
186+
return tud_cdc_n_get_serial_state(_instance).dcd;
187+
}
188+
189+
inline bool Adafruit_USBD_CDC::ri(void) {
190+
return tud_cdc_n_get_serial_state(_instance).ri;
191+
}
192+
193+
void Adafruit_USBD_CDC::cts(bool c) {
194+
cdc_serial_state_t serial_state = tud_cdc_n_get_serial_state(_instance);
195+
serial_state.cts = c;
196+
tud_cdc_n_set_serial_state(_instance, serial_state);
197+
}
198+
199+
void Adafruit_USBD_CDC::dsr(bool c) {
200+
cdc_serial_state_t serial_state = tud_cdc_n_get_serial_state(_instance);
201+
serial_state.dsr = c;
202+
tud_cdc_n_set_serial_state(_instance, serial_state);
203+
}
204+
205+
void Adafruit_USBD_CDC::dcd(bool c) {
206+
cdc_serial_state_t serial_state = tud_cdc_n_get_serial_state(_instance);
207+
serial_state.dcd = c;
208+
tud_cdc_n_set_serial_state(_instance, serial_state);
209+
}
210+
211+
void Adafruit_USBD_CDC::ri(bool c) {
212+
cdc_serial_state_t serial_state = tud_cdc_n_get_serial_state(_instance);
213+
serial_state.ri = c;
214+
tud_cdc_n_set_serial_state(_instance, serial_state);
215+
}
216+
173217
Adafruit_USBD_CDC::operator bool() {
174218
if (!isValid()) {
175219
return false;

src/arduino/Adafruit_USBD_CDC.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,20 @@ class Adafruit_USBD_CDC : public Stream, public Adafruit_USBD_Interface {
5959
uint8_t stopbits(void);
6060
uint8_t paritytype(void);
6161
uint8_t numbits(void);
62-
int dtr(void);
62+
63+
// Flow control bit getters.
64+
int dtr(void); // pre-existing, I don't want to change the return type.
65+
bool rts(void);
66+
bool cts(void);
67+
bool dsr(void);
68+
bool dcd(void);
69+
bool ri(void);
70+
71+
// Flow control bit setters.
72+
void cts(bool c);
73+
void dsr(bool c);
74+
void dcd(bool c);
75+
void ri(bool c);
6376

6477
// Stream API
6578
virtual int available(void);

src/class/cdc/cdc.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,48 @@ typedef struct TU_ATTR_PACKED
412412

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

415+
//--------------------------------------------------------------------+
416+
// Notifications
417+
//--------------------------------------------------------------------+
418+
419+
typedef struct TU_ATTR_PACKED {
420+
uint16_t dcd :1;
421+
uint16_t dsr :1;
422+
uint16_t break_err :1;
423+
uint16_t ri :1;
424+
uint16_t frame_err :1;
425+
uint16_t parity_err :1;
426+
uint16_t overrun_err :1;
427+
uint16_t cts :1; // https://community.st.com/t5/stm32-mcus-products/cts-signal-on-usb-cdc/td-p/325800
428+
uint16_t :8;
429+
} cdc_serial_state_t;
430+
431+
TU_VERIFY_STATIC(sizeof(cdc_serial_state_t) == 2, "size is not correct");
432+
433+
// Add more notifications here. PSTN120.pdf, Section 6.5
434+
typedef struct TU_ATTR_PACKED {
435+
tusb_notification_t header;
436+
union {
437+
cdc_serial_state_t serial_state;
438+
// Add more Notification "Data" payloads here as more are implemented.
439+
};
440+
} cdc_notify_struct_t;
441+
442+
TU_VERIFY_STATIC(sizeof(cdc_notify_struct_t) == 10, "size is not correct");
443+
444+
tu_static const cdc_notify_struct_t cdc_notify_serial_status = {
445+
.header = {
446+
.bmRequestType_bit = {
447+
.recipient = TUSB_REQ_RCPT_INTERFACE,
448+
.type = TUSB_REQ_TYPE_CLASS,
449+
.direction = TUSB_DIR_IN,
450+
},
451+
.bNotification = CDC_NOTIF_SERIAL_STATE,
452+
.wValue = 0,
453+
.wLength = sizeof(cdc_serial_state_t),
454+
}
455+
};
456+
415457
TU_ATTR_PACKED_END // End of all packed definitions
416458
TU_ATTR_BIT_FIELD_ORDER_END
417459

src/class/cdc/cdc_device.c

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ typedef struct {
5959
// Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send)
6060
uint8_t line_state;
6161

62+
// Notify host of flow control bits: CTS, DSR, DCD, RI, and some error flags.
63+
cdc_serial_state_t serial_state;
64+
bool serial_state_changed;
65+
6266
/*------------- From this point, data is not cleared by bus reset -------------*/
6367
char wanted_char;
6468
TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding;
@@ -76,6 +80,7 @@ typedef struct {
7680
// Endpoint Transfer buffer
7781
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EP_BUFSIZE];
7882
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CDC_EP_BUFSIZE];
83+
CFG_TUSB_MEM_ALIGN cdc_notify_struct_t epnotif_buf;
7984
} cdcd_interface_t;
8085

8186
#define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, wanted_char)
@@ -138,6 +143,18 @@ uint8_t tud_cdc_n_get_line_state(uint8_t itf) {
138143
return _cdcd_itf[itf].line_state;
139144
}
140145

146+
cdc_serial_state_t tud_cdc_n_get_serial_state(uint8_t itf) {
147+
return _cdcd_itf[itf].serial_state;
148+
}
149+
150+
void tud_cdc_n_set_serial_state(uint8_t itf, cdc_serial_state_t serial_state) {
151+
if (memcmp(&(_cdcd_itf[itf].serial_state), &serial_state, sizeof(serial_state)) != 0) {
152+
TU_LOG_DRV(" Serial State Changed: %x -> %x\r\n", _cdcd_itf[itf].serial_state, serial_state);
153+
_cdcd_itf[itf].serial_state_changed = true;
154+
}
155+
_cdcd_itf[itf].serial_state = serial_state;
156+
}
157+
141158
void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding) {
142159
(*coding) = _cdcd_itf[itf].line_coding;
143160
}
@@ -326,10 +343,13 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
326343

327344
if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) {
328345
// notification endpoint
329-
tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc;
346+
tusb_desc_endpoint_t desc_ep = *(tusb_desc_endpoint_t const*) p_desc;
347+
TU_LOG_DRV(" Interval before: %d\r\n", desc_ep.bInterval);
348+
349+
desc_ep.bInterval = 1; // Query every frame, 1ms at Full Speed.
330350

331-
TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0);
332-
p_cdc->ep_notif = desc_ep->bEndpointAddress;
351+
TU_ASSERT(usbd_edpt_open(rhport, &desc_ep), 0);
352+
p_cdc->ep_notif = desc_ep.bEndpointAddress;
333353

334354
drv_len += tu_desc_len(p_desc);
335355
p_desc = tu_desc_next(p_desc);
@@ -437,12 +457,13 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
437457
// Identify which interface to use
438458
for (itf = 0; itf < CFG_TUD_CDC; itf++) {
439459
p_cdc = &_cdcd_itf[itf];
440-
if ((ep_addr == p_cdc->ep_out) || (ep_addr == p_cdc->ep_in)) break;
460+
if ((ep_addr == p_cdc->ep_out) || (ep_addr == p_cdc->ep_in) || (ep_addr == p_cdc->ep_notif)) break;
441461
}
442462
TU_ASSERT(itf < CFG_TUD_CDC);
443463

444464
// Received new data
445465
if (ep_addr == p_cdc->ep_out) {
466+
TU_LOG_DRV(" XFer Out\r\n");
446467
tu_fifo_write_n(&p_cdc->rx_ff, p_cdc->epout_buf, (uint16_t) xferred_bytes);
447468

448469
// Check for wanted char and invoke callback if needed
@@ -465,6 +486,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
465486
// Note: This will cause incorrect baudrate set in line coding.
466487
// Though maybe the baudrate is not really important !!!
467488
if (ep_addr == p_cdc->ep_in) {
489+
TU_LOG_DRV(" XFer In\r\n");
468490
// invoke transmit callback to possibly refill tx fifo
469491
if (tud_cdc_tx_complete_cb) tud_cdc_tx_complete_cb(itf);
470492

@@ -479,7 +501,30 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
479501
}
480502
}
481503

482-
// nothing to do with notif endpoint for now
504+
// Notifications
505+
if (ep_addr == p_cdc->ep_notif) {
506+
TU_LOG_DRV(" XFer Notification\r\n");
507+
uint8_t const rhport = 0;
508+
509+
// SERIAL_STATE notification. Send flow control signals.
510+
if (p_cdc->serial_state_changed) {
511+
p_cdc->serial_state_changed = false;
512+
513+
// Build the notification
514+
p_cdc->epnotif_buf = cdc_notify_serial_status;
515+
p_cdc->epnotif_buf.header.wIndex = p_cdc->itf_num;
516+
p_cdc->epnotif_buf.serial_state = p_cdc->serial_state;
517+
518+
// claim endpoint
519+
TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_notif), 0);
520+
521+
// Send notification
522+
return usbd_edpt_xfer(rhport, p_cdc->ep_notif, (uint8_t *) &(p_cdc->epnotif_buf), sizeof(p_cdc->epnotif_buf));
523+
}
524+
else {
525+
// Send a NAK?
526+
}
527+
}
483528

484529
return true;
485530
}

src/class/cdc/cdc_device.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ bool tud_cdc_n_connected(uint8_t itf);
7070
// Get current line state. Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send)
7171
uint8_t tud_cdc_n_get_line_state(uint8_t itf);
7272

73+
// Get current serial state.
74+
cdc_serial_state_t tud_cdc_n_get_serial_state(uint8_t itf);
75+
76+
// Set current serial state.
77+
void tud_cdc_n_set_serial_state(uint8_t itf, cdc_serial_state_t ser_state);
78+
7379
// Get current line encoding: bit rate, stop bits parity etc ..
7480
void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding);
7581

@@ -132,6 +138,14 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t tud_cdc_get_line_state(void) {
132138
return tud_cdc_n_get_line_state(0);
133139
}
134140

141+
TU_ATTR_ALWAYS_INLINE static inline cdc_serial_state_t tud_cdc_get_serial_state(void) {
142+
return tud_cdc_n_get_serial_state(0);
143+
}
144+
145+
TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_set_serial_state(cdc_serial_state_t ser_state) {
146+
return tud_cdc_n_set_serial_state(0, ser_state);
147+
}
148+
135149
TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_get_line_coding(cdc_line_coding_t* coding) {
136150
tud_cdc_n_get_line_coding(0, coding);
137151
}

src/common/tusb_types.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,27 @@ typedef struct TU_ATTR_PACKED {
491491

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

494+
495+
typedef struct TU_ATTR_PACKED {
496+
union {
497+
struct TU_ATTR_PACKED {
498+
uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t.
499+
uint8_t type : 2; ///< Request type tusb_request_type_t.
500+
uint8_t direction : 1; ///< Direction type. tusb_dir_t
501+
} bmRequestType_bit;
502+
503+
uint8_t bmRequestType;
504+
};
505+
506+
uint8_t bNotification;
507+
uint16_t wValue;
508+
uint16_t wIndex;
509+
uint16_t wLength;
510+
} tusb_notification_t;
511+
512+
TU_VERIFY_STATIC( sizeof(tusb_notification_t) == 8, "size is not correct");
513+
514+
494515
TU_ATTR_PACKED_END // End of all packed definitions
495516
TU_ATTR_BIT_FIELD_ORDER_END
496517

0 commit comments

Comments
 (0)