improve USB transmit reliability (but still not ideal)
This commit is contained in:
parent
30638d643b
commit
2494256828
@ -181,6 +181,9 @@ static usbd_device *usb_device;
|
||||
static uint8_t rx_buffer[CDCACM_BUFFER] = {0};
|
||||
static volatile uint8_t rx_i = 0;
|
||||
static volatile uint8_t rx_used = 0;
|
||||
static uint8_t tx_buffer[CDCACM_BUFFER] = {0};
|
||||
static volatile uint8_t tx_i = 0;
|
||||
static volatile uint8_t tx_used = 0;
|
||||
/* show the user how much data received over USB is ready */
|
||||
volatile uint8_t cdcacm_received = 0; // same as rx_used, but since the user can write this variable we don't rely on it
|
||||
|
||||
@ -191,30 +194,33 @@ static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *
|
||||
(void)usbd_dev;
|
||||
|
||||
switch (req->bRequest) {
|
||||
case USB_CDC_REQ_SET_CONTROL_LINE_STATE: {
|
||||
/*
|
||||
* This Linux cdc_acm driver requires this to be implemented
|
||||
* even though it's optional in the CDC spec, and we don't
|
||||
* advertise it in the ACM functional descriptor.
|
||||
*/
|
||||
char local_buf[10];
|
||||
struct usb_cdc_notification *notif = (void *)local_buf;
|
||||
case USB_CDC_REQ_SET_CONTROL_LINE_STATE: {
|
||||
/*
|
||||
* This Linux cdc_acm driver requires this to be implemented
|
||||
* even though it's optional in the CDC spec, and we don't
|
||||
* advertise it in the ACM functional descriptor.
|
||||
*/
|
||||
char local_buf[10];
|
||||
struct usb_cdc_notification *notif = (void *)local_buf;
|
||||
|
||||
/* We echo signals back to host as notification. */
|
||||
notif->bmRequestType = 0xA1;
|
||||
notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
|
||||
notif->wValue = 0;
|
||||
notif->wIndex = 0;
|
||||
notif->wLength = 2;
|
||||
local_buf[8] = req->wValue & 3;
|
||||
local_buf[9] = 0;
|
||||
// usbd_ep_write_packet(0x83, buf, 10);
|
||||
return 1;
|
||||
/* We echo signals back to host as notification. */
|
||||
notif->bmRequestType = 0xA1;
|
||||
notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
|
||||
notif->wValue = 0;
|
||||
notif->wIndex = 0;
|
||||
notif->wLength = 2;
|
||||
local_buf[8] = req->wValue & 3;
|
||||
local_buf[9] = 0;
|
||||
usbd_ep_write_packet(usbd_dev, 0x83, local_buf, 10);
|
||||
return 1;
|
||||
}
|
||||
case USB_CDC_REQ_SET_LINE_CODING:
|
||||
if (*len < sizeof(struct usb_cdc_line_coding))
|
||||
case USB_CDC_REQ_SET_LINE_CODING:
|
||||
if (*len < sizeof(struct usb_cdc_line_coding)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -238,13 +244,32 @@ static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
|
||||
}
|
||||
}
|
||||
|
||||
static void cdcacm_data_tx_cb(usbd_device *usbd_dev, uint8_t ep)
|
||||
{
|
||||
(void)ep;
|
||||
(void)usbd_dev;
|
||||
|
||||
char usb_data[64] = {0}; // buffer to send data
|
||||
uint16_t usb_length = 0; // length of transmitted data
|
||||
|
||||
/* transmit data */
|
||||
if (tx_used) { // copy received data
|
||||
for (usb_length=0; usb_length<sizeof(usb_data) && tx_used; usb_length++) { // only until buffer is full
|
||||
usb_data[usb_length] = tx_buffer[tx_i]; // put data in transmit data
|
||||
tx_i = (tx_i+1)%sizeof(rx_buffer); // update location on buffer
|
||||
tx_used--; // update used size
|
||||
}
|
||||
while(usbd_ep_write_packet(usb_device, 0x82, usb_data, usb_length)==0);
|
||||
}
|
||||
}
|
||||
|
||||
static void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue)
|
||||
{
|
||||
(void)wValue;
|
||||
(void)usbd_dev;
|
||||
|
||||
usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, cdcacm_data_rx_cb);
|
||||
usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL);
|
||||
usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, cdcacm_data_tx_cb);
|
||||
usbd_ep_setup(usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
|
||||
|
||||
usbd_register_control_callback( usbd_dev, USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, cdcacm_control_request);
|
||||
@ -272,13 +297,16 @@ void cdcacm_setup(void)
|
||||
rx_i = 0;
|
||||
rx_used = 0;
|
||||
cdcacm_received = 0;
|
||||
|
||||
/* start sending */
|
||||
usbd_ep_write_packet(usb_device, 0x82, NULL, 0);
|
||||
}
|
||||
|
||||
/* get character from USB CDC ACM (blocking) */
|
||||
char cdcacm_getchar(void)
|
||||
{
|
||||
while (!rx_used) { // idle until data is available
|
||||
__WFI(); // sleep until interrupt;
|
||||
__WFI(); // sleep until interrupt (not sure if it's a good idea here
|
||||
}
|
||||
char to_return = rx_buffer[rx_i]; // get the next available character
|
||||
rx_i = (rx_i+1)%sizeof(rx_buffer); // update used buffer
|
||||
@ -290,7 +318,11 @@ char cdcacm_getchar(void)
|
||||
/* put character on USB CDC ACM (blocking) */
|
||||
void cdcacm_putchar(char c)
|
||||
{
|
||||
while(usbd_ep_write_packet(usb_device, 0x82, &c, 1)==0); // sending single characters at a time isn't very optimal, but I didn't find a way to do it USB request based
|
||||
if (tx_used<sizeof(tx_buffer)) {
|
||||
tx_buffer[(tx_i+tx_used)%sizeof(tx_buffer)] = c; // put character in buffer
|
||||
tx_used++; // update used buffer
|
||||
}
|
||||
usbd_ep_write_packet(usb_device, 0x82, NULL, 0); // trigger tx (not sure why cdcacm_data_tx_cb doesn't work else)
|
||||
}
|
||||
|
||||
void usb_wakeup_isr(void) {
|
||||
|
Loading…
Reference in New Issue
Block a user