mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-22 22:38:08 +00:00
stmhal: vcp+hid style & comments, vcp tx ring buffer
This commit is contained in:
parent
69d7f39b23
commit
87909637bf
@ -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)) {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user