From 87909637bf7fbfaa18f484710ccb1e3ae6abed24 Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Tue, 11 Apr 2017 18:05:52 +0200 Subject: [PATCH] stmhal: vcp+hid style & comments, vcp tx ring buffer --- micropython/firmware/main.c | 32 +++-- micropython/trezorhal/usb.c | 23 +++- micropython/trezorhal/usb_hid-defs.h | 28 +++-- micropython/trezorhal/usb_hid-impl.h | 36 +++--- micropython/trezorhal/usb_vcp-defs.h | 65 +++++----- micropython/trezorhal/usb_vcp-impl.h | 176 ++++++++++++++++----------- 6 files changed, 213 insertions(+), 147 deletions(-) diff --git a/micropython/firmware/main.c b/micropython/firmware/main.c index 7554e9cfe3..9a051d89b4 100644 --- a/micropython/firmware/main.c +++ b/micropython/firmware/main.c @@ -66,19 +66,27 @@ int usb_init_all(void) { }; static uint8_t vcp_rx_buffer[1024]; static uint8_t vcp_rx_packet[64]; + static uint8_t vcp_tx_buffer[1024]; + static uint8_t vcp_tx_packet[64]; // Needs to be same size as vcp_rx_packet static const usb_vcp_info_t vcp_info = { - .iface_num = 0x01, - .data_iface_num = 0x02, - .ep_cmd = USB_EP_DIR_IN | 0x02, - .ep_in = USB_EP_DIR_IN | 0x03, - .ep_out = USB_EP_DIR_OUT | 0x03, - .polling_interval = 10, - .max_data_packet_len = sizeof(vcp_rx_packet), - .rx_packet = vcp_rx_packet, - .rx_buffer_len = sizeof(vcp_rx_buffer), - .rx_buffer = vcp_rx_buffer, - .rx_intr_val = 3, // Ctrl-C - .rx_intr_fn = pendsv_kbd_intr, + .iface_num = 0x01, + .data_iface_num = 0x02, + .ep_cmd = USB_EP_DIR_IN | 0x02, + .ep_in = USB_EP_DIR_IN | 0x03, + .ep_out = USB_EP_DIR_OUT | 0x03, + .polling_interval = 10, + .max_packet_len = sizeof(vcp_rx_packet), + .rx_packet = vcp_rx_packet, + .tx_packet = vcp_tx_packet, + + .rx_buffer_len = sizeof(vcp_rx_buffer), + .rx_buffer = vcp_rx_buffer, + + .tx_buffer_len = sizeof(vcp_tx_buffer), + .tx_buffer = vcp_tx_buffer, + + .rx_intr_byte = 3, // Ctrl-C + .rx_intr_fn = pendsv_kbd_intr, }; if (0 != usb_init(&dev_info)) { diff --git a/micropython/trezorhal/usb.c b/micropython/trezorhal/usb.c index a504e2f7d9..f43e7e9a7c 100644 --- a/micropython/trezorhal/usb.c +++ b/micropython/trezorhal/usb.c @@ -77,11 +77,11 @@ int usb_init(const usb_dev_info_t *dev_info) { usb_config_desc->bLength = sizeof(usb_config_descriptor_t); usb_config_desc->bDescriptorType = USB_DESC_TYPE_CONFIGURATION; usb_config_desc->wTotalLength = sizeof(usb_config_descriptor_t); - usb_config_desc->bNumInterfaces = 0x00; - usb_config_desc->bConfigurationValue = 0x01; // Configuration value - usb_config_desc->iConfiguration = 0x00; // Index of string descriptor describing the configuration + usb_config_desc->bNumInterfaces = 0; + usb_config_desc->bConfigurationValue = 0x01; + usb_config_desc->iConfiguration = 0; usb_config_desc->bmAttributes = 0x80; // 0x80 = bus powered; 0xc0 = self powered - usb_config_desc->bMaxPower = 0xfa; // In units of 2mA + usb_config_desc->bMaxPower = 0xfa; // Maximum Power Consumption in 2mA units // Reset pointer to interface descriptor data usb_next_iface_desc = (usb_interface_descriptor_t *)(usb_config_buf + usb_config_desc->wTotalLength); @@ -298,6 +298,19 @@ static uint8_t usb_class_data_out(USBD_HandleTypeDef *dev, uint8_t ep_num) { return USBD_OK; } +static uint8_t usb_class_sof(USBD_HandleTypeDef *dev) { + for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) { + switch (usb_ifaces[i].type) { + case USB_IFACE_TYPE_VCP: + usb_vcp_class_sof(dev, &usb_ifaces[i].vcp); + break; + default: + break; + } + } + return USBD_OK; +} + static uint8_t *usb_class_get_cfg_desc(uint16_t *length) { *length = usb_config_desc->wTotalLength; return usb_config_buf; @@ -311,7 +324,7 @@ static const USBD_ClassTypeDef usb_class = { .EP0_RxReady = NULL, .DataIn = usb_class_data_in, .DataOut = usb_class_data_out, - .SOF = NULL, + .SOF = usb_class_sof, .IsoINIncomplete = NULL, .IsoOUTIncomplete = NULL, .GetHSConfigDescriptor = usb_class_get_cfg_desc, diff --git a/micropython/trezorhal/usb_hid-defs.h b/micropython/trezorhal/usb_hid-defs.h index 566179fb55..4e74e8793b 100644 --- a/micropython/trezorhal/usb_hid-defs.h +++ b/micropython/trezorhal/usb_hid-defs.h @@ -33,7 +33,12 @@ typedef enum { USB_HID_PROTOCOL_MOUSE = 2, } usb_hid_protocol_t; +/* usb_hid_info_t contains all information for setting up a HID interface. All + * passed pointers need to live at least until the interface is disabled + * (usb_stop is called). */ typedef struct { + const uint8_t *report_desc; // With length of report_desc_len bytes + uint8_t *rx_buffer; // With length of max_packet_len bytes uint8_t iface_num; // Address of this HID interface uint8_t ep_in; // Address of IN endpoint (with the highest bit set) uint8_t ep_out; // Address of OUT endpoint @@ -42,25 +47,26 @@ typedef struct { uint8_t polling_interval; // In units of 1ms uint8_t max_packet_len; // Length of the biggest report and of rx_buffer uint8_t report_desc_len; // Length of report_desc - uint8_t *rx_buffer; // With length of max_packet_len bytes - const uint8_t *report_desc; // With length of report_desc_len bytes } usb_hid_info_t; +/* usb_hid_state_t encapsulates all state used by enabled HID interface. It + * needs to be completely initialized in usb_hid_add and reset in + * usb_hid_class_init. See usb_hid_info_t for details of the configuration + * fields. */ typedef struct { - uint8_t in_idle; // Set to 1 after IN endpoint gets idle - uint8_t protocol; // For SET_PROTOCOL/GET_PROTOCOL setup reqs - uint8_t idle_rate; // For SET_IDLE/GET_IDLE setup reqs - uint8_t alt_setting; // For SET_INTERFACE/GET_INTERFACE setup reqs - uint8_t last_read_len; // Length of data read into rx_buffer - + const usb_hid_descriptor_block_t *desc_block; + const uint8_t *report_desc; + uint8_t *rx_buffer; uint8_t ep_in; uint8_t ep_out; uint8_t max_packet_len; uint8_t report_desc_len; - uint8_t *rx_buffer; - const uint8_t *report_desc; - const usb_hid_descriptor_block_t *desc_block; + uint8_t protocol; // For SET_PROTOCOL/GET_PROTOCOL setup reqs + uint8_t idle_rate; // For SET_IDLE/GET_IDLE setup reqs + uint8_t alt_setting; // For SET_INTERFACE/GET_INTERFACE setup reqs + uint8_t last_read_len; // Length of data read into rx_buffer + uint8_t ep_in_is_idle; // Set to 1 after IN endpoint gets idle } usb_hid_state_t; int usb_hid_add(const usb_hid_info_t *hid_info); diff --git a/micropython/trezorhal/usb_hid-impl.h b/micropython/trezorhal/usb_hid-impl.h index 827dd1a488..233af4f3fd 100644 --- a/micropython/trezorhal/usb_hid-impl.h +++ b/micropython/trezorhal/usb_hid-impl.h @@ -51,18 +51,18 @@ int usb_hid_add(const usb_hid_info_t *info) { d->iface.bLength = sizeof(usb_interface_descriptor_t); d->iface.bDescriptorType = USB_DESC_TYPE_INTERFACE; d->iface.bInterfaceNumber = info->iface_num; - d->iface.bAlternateSetting = 0x00; + d->iface.bAlternateSetting = 0; d->iface.bNumEndpoints = 2; d->iface.bInterfaceClass = USB_CLASS_HID; d->iface.bInterfaceSubClass = info->subclass; d->iface.bInterfaceProtocol = info->protocol; - d->iface.iInterface = 0x00; // Index of string descriptor describing the interface + d->iface.iInterface = 0; // HID descriptor d->hid.bLength = sizeof(usb_hid_descriptor_t); d->hid.bDescriptorType = USB_DESC_TYPE_HID; d->hid.bcdHID = 0x1101; // HID Class Spec release number - d->hid.bCountryCode = 0x00; // Hardware target country + d->hid.bCountryCode = 0; // Hardware target country d->hid.bNumDescriptors = 1; // Number of HID class descriptors d->hid.bReportDescriptorType = USB_DESC_TYPE_REPORT; d->hid.wReportDescriptorLength = info->report_desc_len; @@ -88,17 +88,18 @@ int usb_hid_add(const usb_hid_info_t *info) { // Interface state iface->type = USB_IFACE_TYPE_HID; - iface->hid.in_idle = 1; - iface->hid.protocol = 0; - iface->hid.idle_rate = 0; - iface->hid.alt_setting = 0; - iface->hid.ep_in = info->ep_in; - iface->hid.ep_out = info->ep_out; - iface->hid.max_packet_len = info->max_packet_len; + iface->hid.desc_block = d; + iface->hid.report_desc = info->report_desc; + iface->hid.rx_buffer = info->rx_buffer; + iface->hid.ep_in = info->ep_in; + iface->hid.ep_out = info->ep_out; + iface->hid.max_packet_len = info->max_packet_len; iface->hid.report_desc_len = info->report_desc_len; - iface->hid.rx_buffer = info->rx_buffer; - iface->hid.report_desc = info->report_desc; - iface->hid.desc_block = d; + iface->hid.protocol = 0; + iface->hid.idle_rate = 0; + iface->hid.alt_setting = 0; + iface->hid.last_read_len = 0; + iface->hid.ep_in_is_idle = 1; return 0; } @@ -128,7 +129,7 @@ int usb_hid_can_write(uint8_t iface_num) { if (iface->type != USB_IFACE_TYPE_HID) { return 0; // Invalid interface type } - if (iface->hid.in_idle == 0) { + if (iface->hid.ep_in_is_idle == 0) { return 0; // Last transmission is not over yet } if (usb_dev_handle.dev_state != USBD_STATE_CONFIGURED) { @@ -171,7 +172,7 @@ int usb_hid_write(uint8_t iface_num, const uint8_t *buf, uint32_t len) { } usb_hid_state_t *state = &iface->hid; - state->in_idle = 0; + state->ep_in_is_idle = 0; USBD_LL_Transmit(&usb_dev_handle, state->ep_in, UNCONST(buf), (uint16_t)len); return len; @@ -221,10 +222,11 @@ static int usb_hid_class_init(USBD_HandleTypeDef *dev, usb_hid_state_t *state, u USBD_LL_OpenEP(dev, state->ep_out, USBD_EP_TYPE_INTR, state->max_packet_len); // Reset the state - state->in_idle = 1; state->protocol = 0; state->idle_rate = 0; state->alt_setting = 0; + state->last_read_len = 0; + state->ep_in_is_idle = 1; // Prepare the OUT EP to receive next packet USBD_LL_PrepareReceive(dev, state->ep_out, state->rx_buffer, state->max_packet_len); @@ -301,7 +303,7 @@ static int usb_hid_class_setup(USBD_HandleTypeDef *dev, usb_hid_state_t *state, static uint8_t usb_hid_class_data_in(USBD_HandleTypeDef *dev, usb_hid_state_t *state, uint8_t ep_num) { if ((ep_num | USB_EP_DIR_IN) == state->ep_in) { - state->in_idle = 1; + state->ep_in_is_idle = 1; } return USBD_OK; } diff --git a/micropython/trezorhal/usb_vcp-defs.h b/micropython/trezorhal/usb_vcp-defs.h index 379bc0c7d7..83cc671bd5 100644 --- a/micropython/trezorhal/usb_vcp-defs.h +++ b/micropython/trezorhal/usb_vcp-defs.h @@ -71,51 +71,52 @@ typedef enum { USB_CDC_SPACE_PARITY = 4, } usb_cdc_line_coding_bParityType_t; -typedef void (*usb_vcp_intr_fn_t)(void); - +/* usb_vcp_info_t contains all information for setting up a VCP interface. All + * passed pointers need to live at least until the interface is disabled + * (usb_stop is called). */ typedef struct { - uint8_t iface_num; // Address of this VCP interface - uint8_t data_iface_num; // Address of data interface of the VCP interface association - uint8_t ep_cmd; // Address of IN CMD endpoint (with the highest bit set) - uint8_t ep_in; // Address of IN endpoint (with the highest bit set) - uint8_t ep_out; // Address of OUT endpoint - uint8_t polling_interval; // In units of 1ms - uint8_t max_data_packet_len; - - size_t rx_buffer_len; // Length of rx_buffer, power of 2 - uint8_t *rx_buffer; // With length of rx_buffer_len bytes - uint8_t *rx_packet; // With length of at least max_data_packet_len - - uint8_t rx_intr_val; // Value matched against every received byte - usb_vcp_intr_fn_t rx_intr_fn; // Callback called if rx_intr_val matches - + uint8_t *tx_packet; // Buffer for one packet, with length of at least max_packet_len bytes + uint8_t *tx_buffer; // Buffer for IN EP ring buffer, with length of at least tx_buffer_len bytes + uint8_t *rx_packet; // Buffer for one packet, with length of at least max_packet_len bytes + uint8_t *rx_buffer; // Buffer for OUT EP ring buffer, with length of at least rx_buffer_len bytes + size_t tx_buffer_len; // Length of tx_buffer, needs to be a power of 2 + size_t rx_buffer_len; // Length of rx_buffer, needs to be a power of 2 + void (*rx_intr_fn)(void); // Callback called from usb_vcp_class_data_out IRQ handler if rx_intr_byte matches + uint8_t rx_intr_byte; // Value matched against every received byte + uint8_t iface_num; // Address of this VCP interface + uint8_t data_iface_num; // Address of data interface of the VCP interface association + uint8_t ep_cmd; // Address of IN CMD endpoint (with the highest bit set) + uint8_t ep_in; // Address of IN endpoint (with the highest bit set) + uint8_t ep_out; // Address of OUT endpoint + uint8_t polling_interval; // In units of 1ms + uint8_t max_packet_len; // Length of the biggest packet, and of tx_packet and rx_packet } usb_vcp_info_t; +/* usb_rbuf_t is used internally for the RX/TX buffering. */ typedef struct { size_t cap; volatile size_t read; volatile size_t write; uint8_t *buf; -} ring_buffer_t; +} usb_rbuf_t; +/* usb_vcp_state_t encapsulates all state used by enabled VCP interface. It + * needs to be completely initialized in usb_vcp_add and reset in + * usb_vcp_class_init. See usb_vcp_info_t for details of the configuration + * fields. */ typedef struct { - uint8_t is_connected; - uint8_t in_idle; - - uint8_t data_iface_num; + const usb_vcp_descriptor_block_t *desc_block; + usb_rbuf_t rx_ring; + usb_rbuf_t tx_ring; + uint8_t *rx_packet; + uint8_t *tx_packet; + void (*rx_intr_fn)(void); + uint8_t rx_intr_byte; uint8_t ep_cmd; uint8_t ep_in; uint8_t ep_out; - uint8_t polling_interval; - uint8_t max_data_packet_len; - - uint8_t *rx_packet; - ring_buffer_t rx_ring; - - uint8_t rx_intr_val; - usb_vcp_intr_fn_t rx_intr_fn; - - const usb_vcp_descriptor_block_t *desc_block; + uint8_t max_packet_len; + uint8_t ep_in_is_idle; // Set to 1 after IN endpoint gets idle } usb_vcp_state_t; int usb_vcp_add(const usb_vcp_info_t *vcp_info); diff --git a/micropython/trezorhal/usb_vcp-impl.h b/micropython/trezorhal/usb_vcp-impl.h index f089d287eb..9760c25e4f 100644 --- a/micropython/trezorhal/usb_vcp-impl.h +++ b/micropython/trezorhal/usb_vcp-impl.h @@ -34,23 +34,10 @@ // Class-Specific Request Codes for PSTN subclasses #define USB_CDC_GET_LINE_CODING 0x21 -#define USB_CDC_SET_CONTROL_LINE_STATE 0x22 // Maximal length of packets on IN CMD EP #define USB_CDC_MAX_CMD_PACKET_LEN 0x08 -static inline size_t ring_length(ring_buffer_t *b) { - return (b->write - b->read); -} - -static inline int ring_empty(ring_buffer_t *b) { - return ring_length(b) == 0; -} - -static inline int ring_full(ring_buffer_t *b) { - return ring_length(b) == b->cap; -} - /* usb_vcp_add adds and configures new USB VCP interface according to * configuration options passed in `info`. */ int usb_vcp_add(const usb_vcp_info_t *info) { @@ -82,12 +69,21 @@ int usb_vcp_add(const usb_vcp_info_t *info) { if ((info->rx_buffer_len == 0) || (info->rx_buffer_len & (info->rx_buffer_len - 1)) != 0) { return 1; // Capacity needs to be a power of 2 } + if ((info->tx_buffer_len == 0) || (info->tx_buffer_len & (info->tx_buffer_len - 1)) != 0) { + return 1; // Capacity needs to be a power of 2 + } if (info->rx_buffer == NULL) { return 1; } if (info->rx_packet == NULL) { return 1; } + if (info->tx_buffer == NULL) { + return 1; + } + if (info->tx_packet == NULL) { + return 1; + } // Interface association descriptor d->assoc.bLength = sizeof(usb_interface_assoc_descriptor_t); @@ -97,18 +93,18 @@ int usb_vcp_add(const usb_vcp_info_t *info) { d->assoc.bFunctionClass = USB_CLASS_CDC; d->assoc.bFunctionSubClass = USB_CDC_SUBCLASS_ACM; d->assoc.bFunctionProtocol = USB_CDC_PROTOCOL_AT; - d->assoc.iFunction = 0x00; // Index of string descriptor describing the function + d->assoc.iFunction = 0; // Interface descriptor d->iface_cdc.bLength = sizeof(usb_interface_descriptor_t); d->iface_cdc.bDescriptorType = USB_DESC_TYPE_INTERFACE; d->iface_cdc.bInterfaceNumber = info->iface_num; - d->iface_cdc.bAlternateSetting = 0x00; + d->iface_cdc.bAlternateSetting = 0; d->iface_cdc.bNumEndpoints = 1; d->iface_cdc.bInterfaceClass = USB_CLASS_CDC; d->iface_cdc.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM; d->iface_cdc.bInterfaceProtocol = USB_CDC_PROTOCOL_AT; - d->iface_cdc.iInterface = 0x00; // Index of string descriptor describing the interface + d->iface_cdc.iInterface = 0; // Header Functional Descriptor d->fheader.bFunctionLength = sizeof(usb_vcp_header_descriptor_t); @@ -148,55 +144,76 @@ int usb_vcp_add(const usb_vcp_info_t *info) { d->iface_data.bLength = sizeof(usb_interface_descriptor_t); d->iface_data.bDescriptorType = USB_DESC_TYPE_INTERFACE; d->iface_data.bInterfaceNumber = info->data_iface_num; - d->iface_data.bAlternateSetting = 0x00; + d->iface_data.bAlternateSetting = 0; d->iface_data.bNumEndpoints = 2; d->iface_data.bInterfaceClass = USB_CLASS_DATA; - d->iface_data.bInterfaceSubClass = 0x00; - d->iface_data.bInterfaceProtocol = 0x00; - d->iface_data.iInterface = 0x00; // Index of string descriptor describing the interface + d->iface_data.bInterfaceSubClass = 0; + d->iface_data.bInterfaceProtocol = 0; + d->iface_data.iInterface = 0; // OUT endpoint (receiving) d->ep_out.bLength = sizeof(usb_endpoint_descriptor_t); d->ep_out.bDescriptorType = USB_DESC_TYPE_ENDPOINT; d->ep_out.bEndpointAddress = info->ep_out; d->ep_out.bmAttributes = USBD_EP_TYPE_BULK; - d->ep_out.wMaxPacketSize = info->max_data_packet_len; - d->ep_out.bInterval = 0x00; // Ignored for bulk endpoints + d->ep_out.wMaxPacketSize = info->max_packet_len; + d->ep_out.bInterval = 0; // IN endpoint (sending) d->ep_in.bLength = sizeof(usb_endpoint_descriptor_t); d->ep_in.bDescriptorType = USB_DESC_TYPE_ENDPOINT; d->ep_in.bEndpointAddress = info->ep_in; d->ep_in.bmAttributes = USBD_EP_TYPE_BULK; - d->ep_in.wMaxPacketSize = info->max_data_packet_len; - d->ep_in.bInterval = 0x00; // Ignored for bulk endpoints + d->ep_in.wMaxPacketSize = info->max_packet_len; + d->ep_in.bInterval = 0; // Config descriptor usb_desc_add_iface(sizeof(usb_vcp_descriptor_block_t)); usb_config_desc->bNumInterfaces++; // usb_vcp_descriptor_block_t contains 2 interfaces // Interface state + iface->type = USB_IFACE_TYPE_VCP; - iface->vcp.is_connected = 0; - iface->vcp.in_idle = 1; - iface->vcp.data_iface_num = info->data_iface_num; - iface->vcp.ep_cmd = info->ep_cmd; - iface->vcp.ep_in = info->ep_in; - iface->vcp.ep_out = info->ep_out; - iface->vcp.polling_interval = info->polling_interval; - iface->vcp.max_data_packet_len = info->max_data_packet_len; - iface->vcp.rx_packet = info->rx_packet; - iface->vcp.rx_ring.cap = info->rx_buffer_len; - iface->vcp.rx_ring.buf = info->rx_buffer; - iface->vcp.rx_ring.read = 0; - iface->vcp.rx_ring.write = 0; - iface->vcp.rx_intr_val = info->rx_intr_val; - iface->vcp.rx_intr_fn = info->rx_intr_fn; iface->vcp.desc_block = d; + iface->vcp.rx_ring.buf = info->rx_buffer; + iface->vcp.rx_ring.cap = info->rx_buffer_len; + iface->vcp.rx_ring.read = 0; + iface->vcp.rx_ring.write = 0; + + iface->vcp.tx_ring.buf = info->tx_buffer; + iface->vcp.tx_ring.cap = info->tx_buffer_len; + iface->vcp.tx_ring.read = 0; + iface->vcp.tx_ring.write = 0; + + iface->vcp.rx_packet = info->rx_packet; + iface->vcp.tx_packet = info->tx_packet; + + iface->vcp.rx_intr_fn = info->rx_intr_fn; + iface->vcp.rx_intr_byte = info->rx_intr_byte; + + iface->vcp.ep_cmd = info->ep_cmd; + iface->vcp.ep_in = info->ep_in; + iface->vcp.ep_out = info->ep_out; + iface->vcp.max_packet_len = info->max_packet_len; + + iface->vcp.ep_in_is_idle = 1; + return 0; } +static inline size_t ring_length(usb_rbuf_t *b) { + return (b->write - b->read); +} + +static inline int ring_empty(usb_rbuf_t *b) { + return ring_length(b) == 0; +} + +static inline int ring_full(usb_rbuf_t *b) { + return ring_length(b) == b->cap; +} + int usb_vcp_can_read(uint8_t iface_num) { usb_iface_t *iface = usb_get_iface(iface_num); if (iface == NULL) { @@ -219,14 +236,8 @@ int usb_vcp_can_write(uint8_t iface_num) { if (iface->type != USB_IFACE_TYPE_VCP) { return 0; // Invalid interface type } - if (iface->vcp.in_idle == 0) { - return 0; // Last transmission is not over yet - } - // if (iface->vcp.is_connected == 0) { - // return 0; // Receiving end is not connected - // } - if (usb_dev_handle.dev_state != USBD_STATE_CONFIGURED) { - return 0; // Device is not configured + if (ring_full(&iface->vcp.tx_ring)) { + return 0; // Tx ring buffer is full } return 1; } @@ -242,7 +253,7 @@ int usb_vcp_read(uint8_t iface_num, uint8_t *buf, uint32_t len) { usb_vcp_state_t *state = &iface->vcp; // Read from the rx ring buffer - ring_buffer_t *b = &state->rx_ring; + usb_rbuf_t *b = &state->rx_ring; size_t mask = b->cap - 1; size_t i; for (i = 0; (i < len) && !ring_empty(b); i++) { @@ -262,12 +273,14 @@ int usb_vcp_write(uint8_t iface_num, const uint8_t *buf, uint32_t len) { } usb_vcp_state_t *state = &iface->vcp; - // if (!state->is_connected) { - // return 0; - // } - - state->in_idle = 0; - USBD_LL_Transmit(&usb_dev_handle, state->ep_in, UNCONST(buf), (uint16_t)len); + // Write into the tx ring buffer + usb_rbuf_t *b = &state->tx_ring; + size_t mask = b->cap - 1; + size_t i; + for (i = 0; (i < len) && !ring_full(b); i++) { + b->buf[b->write & mask] = buf[i]; + b->write++; + } return len; } @@ -276,9 +289,9 @@ int usb_vcp_read_blocking(uint8_t iface_num, uint8_t *buf, uint32_t len, uint32_ uint32_t start = HAL_GetTick(); while (!usb_vcp_can_read(iface_num)) { if (HAL_GetTick() - start >= timeout) { - return 0; // Timeout + return 0; // Timeout } - __WFI(); // Enter sleep mode, waiting for interrupt + __WFI(); // Enter sleep mode, waiting for interrupt } return usb_vcp_read(iface_num, buf, len); } @@ -296,18 +309,19 @@ int usb_vcp_write_blocking(uint8_t iface_num, const uint8_t *buf, uint32_t len, static int usb_vcp_class_init(USBD_HandleTypeDef *dev, usb_vcp_state_t *state, uint8_t cfg_idx) { // Open endpoints - USBD_LL_OpenEP(dev, state->ep_in, USBD_EP_TYPE_BULK, state->max_data_packet_len); - USBD_LL_OpenEP(dev, state->ep_out, USBD_EP_TYPE_BULK, state->max_data_packet_len); + USBD_LL_OpenEP(dev, state->ep_in, USBD_EP_TYPE_BULK, state->max_packet_len); + USBD_LL_OpenEP(dev, state->ep_out, USBD_EP_TYPE_BULK, state->max_packet_len); USBD_LL_OpenEP(dev, state->ep_cmd, USBD_EP_TYPE_INTR, USB_CDC_MAX_CMD_PACKET_LEN); // Reset the state state->rx_ring.read = 0; state->rx_ring.write = 0; - state->is_connected = 0; - state->in_idle = 1; + state->tx_ring.read = 0; + state->tx_ring.write = 0; + state->ep_in_is_idle = 1; // Prepare the OUT EP to receive next packet - USBD_LL_PrepareReceive(dev, state->ep_out, state->rx_packet, state->max_data_packet_len); + USBD_LL_PrepareReceive(dev, state->ep_out, state->rx_packet, state->max_packet_len); return USBD_OK; } @@ -340,10 +354,6 @@ static int usb_vcp_class_setup(USBD_HandleTypeDef *dev, usb_vcp_state_t *state, case USB_CDC_GET_LINE_CODING: USBD_CtlSendData(dev, (uint8_t *)(&line_coding), MIN(req->wLength, sizeof(line_coding))); break; - - case USB_CDC_SET_CONTROL_LINE_STATE: - state->is_connected = req->wLength & 1; - break; } break; } @@ -355,7 +365,7 @@ static int usb_vcp_class_setup(USBD_HandleTypeDef *dev, usb_vcp_state_t *state, static uint8_t usb_vcp_class_data_in(USBD_HandleTypeDef *dev, usb_vcp_state_t *state, uint8_t ep_num) { if ((ep_num | USB_EP_DIR_IN) == state->ep_in) { - state->in_idle = 1; + state->ep_in_is_idle = 1; } return USBD_OK; } @@ -365,12 +375,14 @@ static uint8_t usb_vcp_class_data_out(USBD_HandleTypeDef *dev, usb_vcp_state_t * uint32_t len = USBD_LL_GetRxDataSize(dev, ep_num); // Write into the rx ring buffer - ring_buffer_t *b = &state->rx_ring; + usb_rbuf_t *b = &state->rx_ring; size_t mask = b->cap - 1; size_t i; for (i = 0; i < len; i++) { - if ((state->rx_intr_fn != NULL) && (state->rx_packet[i] == state->rx_intr_val)) { - state->rx_intr_fn(); + if (state->rx_intr_fn != NULL) { + if (state->rx_packet[i] == state->rx_intr_byte) { + state->rx_intr_fn(); + } } if (!ring_full(b)) { b->buf[b->write & mask] = state->rx_packet[i]; @@ -379,7 +391,31 @@ static uint8_t usb_vcp_class_data_out(USBD_HandleTypeDef *dev, usb_vcp_state_t * } // Prepare the OUT EP to receive next packet - USBD_LL_PrepareReceive(dev, state->ep_out, state->rx_packet, state->max_data_packet_len); + USBD_LL_PrepareReceive(dev, state->ep_out, state->rx_packet, state->max_packet_len); } return USBD_OK; } + +static uint8_t usb_vcp_class_sof(USBD_HandleTypeDef *dev, usb_vcp_state_t *state) { + if (!state->ep_in_is_idle) { + return USBD_OK; + } + + // Read from the tx ring buffer + usb_rbuf_t *b = &state->tx_ring; + uint8_t *buf = state->tx_packet; + size_t len = state->max_packet_len; + size_t mask = b->cap - 1; + size_t i; + for (i = 0; (i < len) && !ring_empty(b); i++) { + buf[i] = b->buf[b->read & mask]; + b->read++; + } + + if (i > 0) { + state->ep_in_is_idle = 0; + USBD_LL_Transmit(&usb_dev_handle, state->ep_in, buf, (uint16_t)i); + } + + return USBD_OK; +}