improve USB transmit reliability (but still not ideal)

This commit is contained in:
King Kévin 2016-01-19 12:15:03 +01:00
parent 30638d643b
commit 2494256828
1 changed files with 56 additions and 24 deletions

View File

@ -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) {