mbed-os/TESTS/usb_device/basic/USBEndpointTester.cpp

860 lines
39 KiB
C++

/*
* Copyright (c) 2018-2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "stdint.h"
#include "stdlib.h"
#include "USBEndpointTester.h"
#include "mbed_shared_queues.h"
#include "EndpointResolver.h"
#define DEFAULT_CONFIGURATION (1)
#define NUM_PACKETS_UNTIL_ABORT 2
#define NUM_PACKETS_AFTER_ABORT 8
#define EP_ABORT_BUFF_VALUE 0xff
/* If the host ever receives a payload with any byte set to this value,
* the device does not handle abort operation correctly. The buffer
* passed to aborted operation must not be used after call to abort().
*/
#define FORBIDDEN_PAYLOAD_VALUE (NUM_PACKETS_AFTER_ABORT + 1)
#define VENDOR_TEST_CTRL_IN 1
#define VENDOR_TEST_CTRL_OUT 2
#define VENDOR_TEST_CTRL_IN_SIZES 9
#define VENDOR_TEST_CTRL_OUT_SIZES 10
#define VENDOR_TEST_RW_RESTART 11
#define VENDOR_TEST_ABORT_BUFF_CHECK 12
#define EVENT_READY (1 << 0)
#define TEST_SIZE_EP_BULK_MAX (64)
#define TEST_SIZE_EP_BULK_MIN (8)
#define TEST_SIZE_EP_BULK_0 (16)
#define TEST_SIZE_EP_BULK_1 TEST_SIZE_EP_BULK_MAX
#define TEST_SIZE_EP_BULK_2 (32)
#define TEST_SIZE_EP_BULK_3 (16)
#define TEST_SIZE_EP_BULK_4 TEST_SIZE_EP_BULK_MIN
#define TEST_SIZE_EP_INT_MAX (64)
#define TEST_SIZE_EP_INT_MIN (1)
#define TEST_SIZE_EP_INT_0 (16)
#define TEST_SIZE_EP_INT_1 TEST_SIZE_EP_INT_MAX
#define TEST_SIZE_EP_INT_2 (32)
#define TEST_SIZE_EP_INT_3 (16)
#define TEST_SIZE_EP_INT_4 TEST_SIZE_EP_INT_MIN
/* According to USB spec, the wMaxPacketSize for FS isochronous endpoints
* is 1023 B. There are a couple of reasons this value is not used in tests:
* - some of the boards supported by Mbed OS have too little RAM dedicated
* for USB, making EndpointResolve::valid() fail when all the endpoints (2x
* bulk, 2x interrupt, 2x isochronous, 2x control) are configured to use
* the max value of wMaxPacketSize
* (e.g. NUCLEO_F207ZG has 1.25K of endpoint RAM),
* - given a test host with other USB devices on the bus, it is unlikely
* for the test device to be able to reserve the bandwidth associated with
* high wMaxPacketSize for iso endpoints.
*/
#define TEST_SIZE_EP_ISO_MAX (256)
#define TEST_SIZE_EP_ISO_MIN (1)
#define TEST_SIZE_EP_ISO_0 (0)
#define TEST_SIZE_EP_ISO_1 (0)
#define TEST_SIZE_EP_ISO_2 (0)
#define TEST_SIZE_EP_ISO_3 (0)
#define TEST_SIZE_EP_ISO_4 (0)
#define EP_BULK_OUT 0
#define EP_BULK_IN 1
#define EP_INT_OUT 2
#define EP_INT_IN 3
#define EP_ISO_OUT 4
#define EP_ISO_IN 5
USBEndpointTester::ep_config_t USBEndpointTester::_intf_config_max[NUM_ENDPOINTS] = {
{ false, USB_EP_TYPE_BULK, TEST_SIZE_EP_BULK_MAX, static_cast<ep_cb_t>(&USBEndpointTester::_cb_bulk_out) },
{ true, USB_EP_TYPE_BULK, TEST_SIZE_EP_BULK_MAX, static_cast<ep_cb_t>(&USBEndpointTester::_cb_bulk_in) },
{ false, USB_EP_TYPE_INT, TEST_SIZE_EP_INT_MAX, static_cast<ep_cb_t>(&USBEndpointTester::_cb_int_out) },
{ true, USB_EP_TYPE_INT, TEST_SIZE_EP_INT_MAX, static_cast<ep_cb_t>(&USBEndpointTester::_cb_int_in) },
{ false, USB_EP_TYPE_ISO, TEST_SIZE_EP_ISO_MAX, static_cast<ep_cb_t>(&USBEndpointTester::_cb_iso_out) },
{ true, USB_EP_TYPE_ISO, TEST_SIZE_EP_ISO_MAX, static_cast<ep_cb_t>(&USBEndpointTester::_cb_iso_in) },
};
USBEndpointTester::ep_config_t USBEndpointTester::_intf_config0[NUM_ENDPOINTS] = {
{ false, USB_EP_TYPE_BULK, TEST_SIZE_EP_BULK_0, NULL },
{ true, USB_EP_TYPE_BULK, TEST_SIZE_EP_BULK_0, NULL },
{ false, USB_EP_TYPE_INT, TEST_SIZE_EP_INT_0, NULL },
{ true, USB_EP_TYPE_INT, TEST_SIZE_EP_INT_0, NULL },
{ false, USB_EP_TYPE_ISO, TEST_SIZE_EP_ISO_0, NULL },
{ true, USB_EP_TYPE_ISO, TEST_SIZE_EP_ISO_0, NULL },
};
USBEndpointTester::ep_config_t USBEndpointTester::_intf_config1[NUM_ENDPOINTS] = {
{ false, USB_EP_TYPE_BULK, TEST_SIZE_EP_BULK_1, static_cast<ep_cb_t>(&USBEndpointTester::_cb_bulk_out) },
{ true, USB_EP_TYPE_BULK, TEST_SIZE_EP_BULK_1, static_cast<ep_cb_t>(&USBEndpointTester::_cb_bulk_in) },
{ false, USB_EP_TYPE_INT, TEST_SIZE_EP_INT_1, static_cast<ep_cb_t>(&USBEndpointTester::_cb_int_out) },
{ true, USB_EP_TYPE_INT, TEST_SIZE_EP_INT_1, static_cast<ep_cb_t>(&USBEndpointTester::_cb_int_in) },
{ false, USB_EP_TYPE_ISO, TEST_SIZE_EP_ISO_1, static_cast<ep_cb_t>(&USBEndpointTester::_cb_iso_out) },
{ true, USB_EP_TYPE_ISO, TEST_SIZE_EP_ISO_1, static_cast<ep_cb_t>(&USBEndpointTester::_cb_iso_in) },
};
USBEndpointTester::ep_config_t USBEndpointTester::_intf_config2[NUM_ENDPOINTS] = {
{ false, USB_EP_TYPE_BULK, TEST_SIZE_EP_BULK_2, static_cast<ep_cb_t>(&USBEndpointTester::_cb_bulk_out) },
{ true, USB_EP_TYPE_BULK, TEST_SIZE_EP_BULK_2, static_cast<ep_cb_t>(&USBEndpointTester::_cb_bulk_in) },
{ false, USB_EP_TYPE_INT, TEST_SIZE_EP_INT_2, static_cast<ep_cb_t>(&USBEndpointTester::_cb_int_out) },
{ true, USB_EP_TYPE_INT, TEST_SIZE_EP_INT_2, static_cast<ep_cb_t>(&USBEndpointTester::_cb_int_in) },
{ false, USB_EP_TYPE_ISO, TEST_SIZE_EP_ISO_2, static_cast<ep_cb_t>(&USBEndpointTester::_cb_iso_out) },
{ true, USB_EP_TYPE_ISO, TEST_SIZE_EP_ISO_2, static_cast<ep_cb_t>(&USBEndpointTester::_cb_iso_in) },
};
USBEndpointTester::ep_config_t USBEndpointTester::_intf_config3[NUM_ENDPOINTS] = {
{ false, USB_EP_TYPE_BULK, TEST_SIZE_EP_BULK_3, static_cast<ep_cb_t>(&USBEndpointTester::_cb_bulk_out) },
{ true, USB_EP_TYPE_BULK, TEST_SIZE_EP_BULK_3, static_cast<ep_cb_t>(&USBEndpointTester::_cb_bulk_in) },
{ false, USB_EP_TYPE_INT, TEST_SIZE_EP_INT_3, static_cast<ep_cb_t>(&USBEndpointTester::_cb_int_out) },
{ true, USB_EP_TYPE_INT, TEST_SIZE_EP_INT_3, static_cast<ep_cb_t>(&USBEndpointTester::_cb_int_in) },
{ false, USB_EP_TYPE_ISO, TEST_SIZE_EP_ISO_3, static_cast<ep_cb_t>(&USBEndpointTester::_cb_iso_out) },
{ true, USB_EP_TYPE_ISO, TEST_SIZE_EP_ISO_3, static_cast<ep_cb_t>(&USBEndpointTester::_cb_iso_in) },
};
USBEndpointTester::ep_config_t USBEndpointTester::_intf_config4[NUM_ENDPOINTS] = {
{ false, USB_EP_TYPE_BULK, TEST_SIZE_EP_BULK_4, static_cast<ep_cb_t>(&USBEndpointTester::_cb_bulk_out) },
{ true, USB_EP_TYPE_BULK, TEST_SIZE_EP_BULK_4, static_cast<ep_cb_t>(&USBEndpointTester::_cb_bulk_in) },
{ false, USB_EP_TYPE_INT, TEST_SIZE_EP_INT_4, static_cast<ep_cb_t>(&USBEndpointTester::_cb_int_out) },
{ true, USB_EP_TYPE_INT, TEST_SIZE_EP_INT_4, static_cast<ep_cb_t>(&USBEndpointTester::_cb_int_in) },
{ false, USB_EP_TYPE_ISO, TEST_SIZE_EP_ISO_4, static_cast<ep_cb_t>(&USBEndpointTester::_cb_iso_out) },
{ true, USB_EP_TYPE_ISO, TEST_SIZE_EP_ISO_4, static_cast<ep_cb_t>(&USBEndpointTester::_cb_iso_in) },
};
USBEndpointTester::USBEndpointTester(USBPhy *phy, uint16_t vendor_id, uint16_t product_id, uint16_t product_release,
bool abort_transfer_test) :
USBDevice(phy, vendor_id, product_id, product_release), _abort_transfer_test(abort_transfer_test), _endpoint_configs(
&_intf_config_max)
{
_cnt_cb_set_conf = 0;
_cnt_cb_set_intf = 0;
_cnt_cb_bulk_out = 0;
_cnt_cb_bulk_in = 0;
_cnt_cb_int_out = 0;
_cnt_cb_int_in = 0;
_cnt_cb_iso_out = 0;
_cnt_cb_iso_in = 0;
_num_packets_bulk_out_abort = 0;
_num_packets_bulk_in_abort = 0;
_num_packets_int_out_abort = 0;
_num_packets_int_in_abort = 0;
EndpointResolver resolver(endpoint_table());
resolver.endpoint_ctrl(64);
ep_config_t *epc = NULL;
for (size_t i = 0; i < NUM_ENDPOINTS; i++) {
epc = &((*_endpoint_configs)[i]);
_endpoints[i] = resolver.next_free_endpoint(epc->dir_in, epc->type, epc->max_packet);
_endpoint_buffs[i] = (uint8_t *) calloc(epc->max_packet, sizeof(uint8_t));
MBED_ASSERT(_endpoint_buffs[i] != NULL);
}
MBED_ASSERT(resolver.valid());
queue = mbed::mbed_highprio_event_queue();
configuration_desc(0);
init();
USBDevice::connect();
flags.wait_any(EVENT_READY, osWaitForever, false);
}
USBEndpointTester::~USBEndpointTester()
{
for (size_t i = 0; i < NUM_ENDPOINTS; i++) {
if (_endpoint_buffs[i] != NULL) {
free(_endpoint_buffs[i]);
}
}
deinit();
}
const char *USBEndpointTester::get_desc_string(const uint8_t *desc)
{
static char ret_string[128] = { };
const uint8_t desc_size = desc[0] - 2;
const uint8_t *desc_str = &desc[2];
uint32_t j = 0;
for (uint32_t i = 0; i < desc_size; i += 2, j++) {
ret_string[j] = desc_str[i];
}
ret_string[j] = '\0';
return ret_string;
}
const char *USBEndpointTester::get_serial_desc_string()
{
return get_desc_string(string_iserial_desc());
}
void USBEndpointTester::callback_state_change(DeviceState new_state)
{
if (new_state == Configured) {
flags.set(EVENT_READY);
} else {
flags.clear(EVENT_READY);
}
}
void USBEndpointTester::callback_request(const setup_packet_t *setup)
{
/* Called in ISR context */
RequestResult result = PassThrough;
uint8_t *data = NULL;
uint32_t size = 0;
/* Process vendor-specific requests */
if (setup->bmRequestType.Type == VENDOR_TYPE) {
switch (setup->bRequest) {
case VENDOR_TEST_CTRL_IN:
result = Send;
data = ctrl_buf;
size = setup->wValue < sizeof(ctrl_buf) ? setup->wValue : sizeof(ctrl_buf);
break;
case VENDOR_TEST_CTRL_OUT:
result = Receive;
data = ctrl_buf;
size = setup->wValue < 8 ? setup->wValue : 8;
break;
case VENDOR_TEST_CTRL_IN_SIZES:
result = Send;
data = ctrl_buf;
size = setup->wLength;
break;
case VENDOR_TEST_CTRL_OUT_SIZES:
result = Receive;
data = ctrl_buf;
size = setup->wValue;
break;
case VENDOR_TEST_RW_RESTART:
result = (_request_rw_restart(setup)) ? Success : Failure;
break;
case VENDOR_TEST_ABORT_BUFF_CHECK:
result = Send;
ctrl_buf[0] = _request_abort_buff_check(setup);
data = ctrl_buf;
size = 1;
break;
default:
result = PassThrough;
break;
}
}
complete_request(result, data, size);
}
bool USBEndpointTester::_request_rw_restart(const setup_packet_t *setup)
{
assert_locked();
ep_config_t *epc = NULL;
for (size_t i = 0; i < NUM_ENDPOINTS; i++) {
epc = &((*_endpoint_configs)[i]);
endpoint_abort(_endpoints[i]);
if (epc->dir_in == false) {
// Wait for data on every OUT endpoint
read_start(_endpoints[i], _endpoint_buffs[i], epc->max_packet);
}
}
return true;
}
bool USBEndpointTester::_request_abort_buff_check(const setup_packet_t *setup)
{
assert_locked();
if (setup->bmRequestType.Recipient != ENDPOINT_RECIPIENT) {
return false;
}
size_t ep_index = NUM_ENDPOINTS;
for (size_t i = 0; i < NUM_ENDPOINTS; i++) {
if (_endpoints[i] == setup->wIndex) {
ep_index = i;
break;
}
}
if (ep_index == NUM_ENDPOINTS) {
return false;
}
if (_endpoint_buffs[ep_index] == NULL) {
return false;
}
for (size_t i = 0; i < (*_endpoint_configs)[ep_index].max_packet; i++) {
if (_endpoint_buffs[ep_index][i] != EP_ABORT_BUFF_VALUE) {
return false;
}
}
return true;
}
void USBEndpointTester::callback_request_xfer_done(const setup_packet_t *setup, bool aborted)
{
if (aborted) {
complete_request_xfer_done(false);
return;
}
bool result = false;
if (setup->bmRequestType.Type == VENDOR_TYPE) {
switch (setup->bRequest) {
case VENDOR_TEST_CTRL_IN:
result = true;
break;
case VENDOR_TEST_CTRL_OUT:
result = true;
break;
case VENDOR_TEST_CTRL_OUT_SIZES:
result = true;
break;
case VENDOR_TEST_CTRL_IN_SIZES:
result = true;
break;
case VENDOR_TEST_ABORT_BUFF_CHECK:
result = true;
break;
default:
result = false;
break;
}
}
complete_request_xfer_done(result);
}
void USBEndpointTester::callback_set_configuration(uint8_t configuration)
{
_cnt_cb_set_conf++;
if (configuration != DEFAULT_CONFIGURATION) {
complete_set_configuration(false);
return;
}
// Configure endpoints > 0
bool status = _setup_interface(0, 0);
complete_set_configuration(status);
}
bool USBEndpointTester::_setup_interface(uint16_t interface, uint8_t alternate)
{
if (interface != 0) {
return false;
}
switch (alternate) {
case 0:
_endpoint_configs = &_intf_config0;
break;
case 1:
_endpoint_configs = &_intf_config1;
break;
case 2:
_endpoint_configs = &_intf_config2;
break;
case 3:
_endpoint_configs = &_intf_config3;
break;
case 4:
_endpoint_configs = &_intf_config4;
break;
default:
return false;
}
_setup_non_zero_endpoints();
if (_abort_transfer_test && alternate >= 1) {
_num_packets_bulk_out_abort = 0;
_num_packets_bulk_in_abort = 0;
_num_packets_int_out_abort = 0;
_num_packets_int_in_abort = 0;
start_ep_in_abort_test();
}
return true;
}
void USBEndpointTester::_setup_non_zero_endpoints()
{
ep_config_t *epc = NULL;
for (size_t i = 0; i < NUM_ENDPOINTS; i++) {
epc = &((*_endpoint_configs)[i]);
endpoint_add(_endpoints[i], epc->max_packet, epc->type, epc->callback);
if (epc->callback == NULL) {
continue;
}
if (epc->dir_in == false) {
// Wait for data on every OUT endpoint
read_start(_endpoints[i], _endpoint_buffs[i], epc->max_packet);
}
}
}
void USBEndpointTester::callback_set_interface(uint16_t interface, uint8_t alternate)
{
_cnt_cb_set_intf++;
if (interface != 0 || alternate > 4) {
complete_set_interface(false);
return;
}
for (size_t i = 0; i < NUM_ENDPOINTS; i++) {
endpoint_abort(_endpoints[i]);
endpoint_remove(_endpoints[i]);
}
bool status = _setup_interface(interface, alternate);
complete_set_interface(status);
}
#define CONFIG1_DESC_SIZE (CONFIGURATION_DESCRIPTOR_LENGTH \
+ 5 * (INTERFACE_DESCRIPTOR_LENGTH + NUM_ENDPOINTS * ENDPOINT_DESCRIPTOR_LENGTH) )
const uint8_t *USBEndpointTester::configuration_desc(uint8_t index)
{
static const uint8_t config_1_descriptor[] = {
// configuration descriptor
CONFIGURATION_DESCRIPTOR_LENGTH, // bLength
CONFIGURATION_DESCRIPTOR, // bDescriptorType
LSB(CONFIG1_DESC_SIZE), // wTotalLength (LSB)
MSB(CONFIG1_DESC_SIZE), // wTotalLength (MSB)
1, // bNumInterfaces
1, // bConfigurationValue
0, // iConfiguration
0x80, // bmAttributes
50, // bMaxPower
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
INTERFACE_DESCRIPTOR_LENGTH,// bLength
INTERFACE_DESCRIPTOR, // bDescriptorType
0, // bInterfaceNumber
0, // bAlternateSetting
NUM_ENDPOINTS, // bNumEndpoints
0xFF, // bInterfaceClass
0xFF, // bInterfaceSubClass
0xFF, // bInterfaceProtocol
0, // iInterface
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_BULK_OUT], // bEndpointAddress
E_BULK, // bmAttributes
(uint8_t)(LSB(_intf_config0[EP_BULK_OUT].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config0[EP_BULK_OUT].max_packet)), // wMaxPacketSize (MSB)
0, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_BULK_IN], // bEndpointAddress
E_BULK, // bmAttributes
(uint8_t)(LSB(_intf_config0[EP_BULK_IN].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config0[EP_BULK_IN].max_packet)), // wMaxPacketSize (MSB)
0, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_INT_OUT], // bEndpointAddress
E_INTERRUPT, // bmAttributes
(uint8_t)(LSB(_intf_config0[EP_INT_OUT].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config0[EP_INT_OUT].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_INT_IN], // bEndpointAddress
E_INTERRUPT, // bmAttributes
(uint8_t)(LSB(_intf_config0[EP_INT_IN].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config0[EP_INT_IN].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_ISO_OUT], // bEndpointAddress
E_ISOCHRONOUS, // bmAttributes
(uint8_t)(LSB(_intf_config0[EP_ISO_OUT].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config0[EP_ISO_OUT].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_ISO_IN], // bEndpointAddress
E_ISOCHRONOUS, // bmAttributes
(uint8_t)(LSB(_intf_config0[EP_ISO_IN].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config0[EP_ISO_IN].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
INTERFACE_DESCRIPTOR_LENGTH,// bLength
INTERFACE_DESCRIPTOR, // bDescriptorType
0, // bInterfaceNumber
1, // bAlternateSetting
NUM_ENDPOINTS, // bNumEndpoints
0xFF, // bInterfaceClass
0xFF, // bInterfaceSubClass
0xFF, // bInterfaceProtocol
0, // iInterface
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_BULK_OUT], // bEndpointAddress
E_BULK, // bmAttributes
(uint8_t)(LSB(_intf_config1[EP_BULK_OUT].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config1[EP_BULK_OUT].max_packet)), // wMaxPacketSize (MSB)
0, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_BULK_IN], // bEndpointAddress
E_BULK, // bmAttributes
(uint8_t)(LSB(_intf_config1[EP_BULK_IN].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config1[EP_BULK_IN].max_packet)), // wMaxPacketSize (MSB)
0, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_INT_OUT], // bEndpointAddress
E_INTERRUPT, // bmAttributes
(uint8_t)(LSB(_intf_config1[EP_INT_OUT].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config1[EP_INT_OUT].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_INT_IN], // bEndpointAddress
E_INTERRUPT, // bmAttributes
(uint8_t)(LSB(_intf_config1[EP_INT_IN].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config1[EP_INT_IN].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_ISO_OUT], // bEndpointAddress
E_ISOCHRONOUS, // bmAttributes
(uint8_t)(LSB(_intf_config1[EP_ISO_OUT].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config1[EP_ISO_OUT].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_ISO_IN], // bEndpointAddress
E_ISOCHRONOUS, // bmAttributes
(uint8_t)(LSB(_intf_config1[EP_ISO_IN].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config1[EP_ISO_IN].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
INTERFACE_DESCRIPTOR_LENGTH,// bLength
INTERFACE_DESCRIPTOR, // bDescriptorType
0, // bInterfaceNumber
2, // bAlternateSetting
NUM_ENDPOINTS, // bNumEndpoints
0xFF, // bInterfaceClass
0xFF, // bInterfaceSubClass
0xFF, // bInterfaceProtocol
0, // iInterface
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_BULK_OUT], // bEndpointAddress
E_BULK, // bmAttributes
(uint8_t)(LSB(_intf_config2[EP_BULK_OUT].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config2[EP_BULK_OUT].max_packet)), // wMaxPacketSize (MSB)
0, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_BULK_IN], // bEndpointAddress
E_BULK, // bmAttributes
(uint8_t)(LSB(_intf_config2[EP_BULK_IN].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config2[EP_BULK_IN].max_packet)), // wMaxPacketSize (MSB)
0, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_INT_OUT], // bEndpointAddress
E_INTERRUPT, // bmAttributes
(uint8_t)(LSB(_intf_config2[EP_INT_OUT].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config2[EP_INT_OUT].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_INT_IN], // bEndpointAddress
E_INTERRUPT, // bmAttributes
(uint8_t)(LSB(_intf_config2[EP_INT_IN].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config2[EP_INT_IN].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_ISO_OUT], // bEndpointAddress
E_ISOCHRONOUS, // bmAttributes
(uint8_t)(LSB(_intf_config2[EP_ISO_OUT].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config2[EP_ISO_OUT].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_ISO_IN], // bEndpointAddress
E_ISOCHRONOUS, // bmAttributes
(uint8_t)(LSB(_intf_config2[EP_ISO_IN].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config2[EP_ISO_IN].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
INTERFACE_DESCRIPTOR_LENGTH,// bLength
INTERFACE_DESCRIPTOR, // bDescriptorType
0, // bInterfaceNumber
3, // bAlternateSetting
NUM_ENDPOINTS, // bNumEndpoints
0xFF, // bInterfaceClass
0xFF, // bInterfaceSubClass
0xFF, // bInterfaceProtocol
0, // iInterface
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_BULK_OUT], // bEndpointAddress
E_BULK, // bmAttributes
(uint8_t)(LSB(_intf_config3[EP_BULK_OUT].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config3[EP_BULK_OUT].max_packet)), // wMaxPacketSize (MSB)
0, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_BULK_IN], // bEndpointAddress
E_BULK, // bmAttributes
(uint8_t)(LSB(_intf_config3[EP_BULK_IN].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config3[EP_BULK_IN].max_packet)), // wMaxPacketSize (MSB)
0, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_INT_OUT], // bEndpointAddress
E_INTERRUPT, // bmAttributes
(uint8_t)(LSB(_intf_config3[EP_INT_OUT].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config3[EP_INT_OUT].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_INT_IN], // bEndpointAddress
E_INTERRUPT, // bmAttributes
(uint8_t)(LSB(_intf_config3[EP_INT_IN].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config3[EP_INT_IN].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_ISO_OUT], // bEndpointAddress
E_ISOCHRONOUS, // bmAttributes
(uint8_t)(LSB(_intf_config3[EP_ISO_OUT].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config3[EP_ISO_OUT].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_ISO_IN], // bEndpointAddress
E_ISOCHRONOUS, // bmAttributes
(uint8_t)(LSB(_intf_config3[EP_ISO_IN].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config3[EP_ISO_IN].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
INTERFACE_DESCRIPTOR_LENGTH,// bLength
INTERFACE_DESCRIPTOR, // bDescriptorType
0, // bInterfaceNumber
4, // bAlternateSetting
NUM_ENDPOINTS, // bNumEndpoints
0xFF, // bInterfaceClass
0xFF, // bInterfaceSubClass
0xFF, // bInterfaceProtocol
0, // iInterface
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_BULK_OUT], // bEndpointAddress
E_BULK, // bmAttributes
(uint8_t)(LSB(_intf_config4[EP_BULK_OUT].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config4[EP_BULK_OUT].max_packet)), // wMaxPacketSize (MSB)
0, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_BULK_IN], // bEndpointAddress
E_BULK, // bmAttributes
(uint8_t)(LSB(_intf_config4[EP_BULK_IN].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config4[EP_BULK_IN].max_packet)), // wMaxPacketSize (MSB)
0, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_INT_OUT], // bEndpointAddress
E_INTERRUPT, // bmAttributes
(uint8_t)(LSB(_intf_config4[EP_INT_OUT].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config4[EP_INT_OUT].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_INT_IN], // bEndpointAddress
E_INTERRUPT, // bmAttributes
(uint8_t)(LSB(_intf_config4[EP_INT_IN].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config4[EP_INT_IN].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_ISO_OUT], // bEndpointAddress
E_ISOCHRONOUS, // bmAttributes
(uint8_t)(LSB(_intf_config4[EP_ISO_OUT].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config4[EP_ISO_OUT].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
_endpoints[EP_ISO_IN], // bEndpointAddress
E_ISOCHRONOUS, // bmAttributes
(uint8_t)(LSB(_intf_config4[EP_ISO_IN].max_packet)), // wMaxPacketSize (LSB)
(uint8_t)(MSB(_intf_config4[EP_ISO_IN].max_packet)), // wMaxPacketSize (MSB)
1, // bInterval
};
if (index == 0) {
return config_1_descriptor;
} else {
return NULL;
}
}
void USBEndpointTester::_cb_bulk_out()
{
_cnt_cb_bulk_out++;
uint32_t rx_size = read_finish(_endpoints[EP_BULK_OUT]);
if (_abort_transfer_test == false) {
// Send data back to host using the IN endpoint.
memset(_endpoint_buffs[EP_BULK_IN], 0, (*_endpoint_configs)[EP_BULK_IN].max_packet);
memcpy(_endpoint_buffs[EP_BULK_IN], _endpoint_buffs[EP_BULK_OUT], rx_size);
write_start(_endpoints[EP_BULK_IN], _endpoint_buffs[EP_BULK_IN], rx_size);
} else {
// Abort the transfer if enough data was received.
_num_packets_bulk_out_abort++;
if (_num_packets_bulk_out_abort == NUM_PACKETS_UNTIL_ABORT) {
// Set every byte of the buffer to a known value.
memset(_endpoint_buffs[EP_BULK_OUT], EP_ABORT_BUFF_VALUE, (*_endpoint_configs)[EP_BULK_OUT].max_packet);
}
read_start(_endpoints[EP_BULK_OUT], _endpoint_buffs[EP_BULK_OUT], (*_endpoint_configs)[EP_BULK_OUT].max_packet);
if (_num_packets_bulk_out_abort == NUM_PACKETS_UNTIL_ABORT) {
endpoint_abort(_endpoints[EP_BULK_OUT]);
}
}
}
void USBEndpointTester::_cb_bulk_in()
{
_cnt_cb_bulk_in++;
write_finish(_endpoints[EP_BULK_IN]);
if (_abort_transfer_test == false) {
// Receive more data from the host using the OUT endpoint.
read_start(_endpoints[EP_BULK_OUT], _endpoint_buffs[EP_BULK_OUT], (*_endpoint_configs)[EP_BULK_OUT].max_packet);
} else {
_num_packets_bulk_in_abort++;
if (_num_packets_bulk_in_abort >= NUM_PACKETS_UNTIL_ABORT + NUM_PACKETS_AFTER_ABORT) {
return;
}
// Abort the transfer if enough data was sent.
memset(_endpoint_buffs[EP_BULK_IN], _num_packets_bulk_in_abort, (*_endpoint_configs)[EP_BULK_IN].max_packet);
write_start(_endpoints[EP_BULK_IN], _endpoint_buffs[EP_BULK_IN], (*_endpoint_configs)[EP_BULK_IN].max_packet);
if (_num_packets_bulk_in_abort == NUM_PACKETS_UNTIL_ABORT) {
endpoint_abort(_endpoints[EP_BULK_IN]);
// Verify that buffer given in write_start is not used after the
// call to endpoint_abort(), by changing the buffer contents.
// The test will fail if the host receives new buffer content.
memset(_endpoint_buffs[EP_BULK_IN], FORBIDDEN_PAYLOAD_VALUE, (*_endpoint_configs)[EP_BULK_IN].max_packet);
}
}
}
void USBEndpointTester::_cb_int_out()
{
_cnt_cb_int_out++;
uint32_t rx_size = read_finish(_endpoints[EP_INT_OUT]);
if (_abort_transfer_test == false) {
// Send data back to host using the IN endpoint.
memset(_endpoint_buffs[EP_INT_IN], 0, (*_endpoint_configs)[EP_INT_IN].max_packet);
memcpy(_endpoint_buffs[EP_INT_IN], _endpoint_buffs[EP_INT_OUT], rx_size);
write_start(_endpoints[EP_INT_IN], _endpoint_buffs[EP_INT_IN], rx_size);
} else {
// Abort the transfer if enough data was received.
_num_packets_int_out_abort++;
if (_num_packets_int_out_abort == NUM_PACKETS_UNTIL_ABORT) {
// Set every byte of the buffer to a known value.
memset(_endpoint_buffs[EP_INT_OUT], EP_ABORT_BUFF_VALUE, (*_endpoint_configs)[EP_INT_OUT].max_packet);
}
read_start(_endpoints[EP_INT_OUT], _endpoint_buffs[EP_INT_OUT], (*_endpoint_configs)[EP_INT_OUT].max_packet);
if (_num_packets_int_out_abort == NUM_PACKETS_UNTIL_ABORT) {
endpoint_abort(_endpoints[EP_INT_OUT]);
}
}
}
void USBEndpointTester::_cb_int_in()
{
_cnt_cb_int_in++;
write_finish(_endpoints[EP_INT_IN]);
if (_abort_transfer_test == false) {
// Receive more data from the host using the OUT endpoint.
read_start(_endpoints[EP_INT_OUT], _endpoint_buffs[EP_INT_OUT], (*_endpoint_configs)[EP_INT_OUT].max_packet);
} else {
_num_packets_int_in_abort++;
if (_num_packets_int_in_abort >= NUM_PACKETS_UNTIL_ABORT + NUM_PACKETS_AFTER_ABORT) {
return;
}
// Abort the transfer if enough data was sent.
memset(_endpoint_buffs[EP_INT_IN], _num_packets_int_in_abort, (*_endpoint_configs)[EP_INT_IN].max_packet);
write_start(_endpoints[EP_INT_IN], _endpoint_buffs[EP_INT_IN], (*_endpoint_configs)[EP_INT_IN].max_packet);
if (_num_packets_int_in_abort == NUM_PACKETS_UNTIL_ABORT) {
endpoint_abort(_endpoints[EP_INT_IN]);
// Verify that buffer given in write_start is not used after the
// call to endpoint_abort(), by changing the buffer contents.
// The test will fail if the host receives new buffer content.
memset(_endpoint_buffs[EP_INT_IN], FORBIDDEN_PAYLOAD_VALUE, (*_endpoint_configs)[EP_INT_IN].max_packet);
}
}
}
void USBEndpointTester::_cb_iso_out()
{
_cnt_cb_iso_out++;
uint32_t rx_size = read_finish(_endpoints[EP_ISO_OUT]);
// Send data back to host using the IN endpoint.
memset(_endpoint_buffs[EP_ISO_IN], 0, (*_endpoint_configs)[EP_ISO_IN].max_packet);
memcpy(_endpoint_buffs[EP_ISO_IN], _endpoint_buffs[EP_ISO_OUT], rx_size);
write_start(_endpoints[EP_ISO_IN], _endpoint_buffs[EP_ISO_IN], rx_size);
}
void USBEndpointTester::_cb_iso_in()
{
_cnt_cb_iso_in++;
write_finish(_endpoints[EP_ISO_IN]);
// Receive more data from the host using the OUT endpoint.
read_start(_endpoints[EP_ISO_OUT], _endpoint_buffs[EP_ISO_OUT], (*_endpoint_configs)[EP_ISO_OUT].max_packet);
}
void USBEndpointTester::start_ep_in_abort_test()
{
memset(_endpoint_buffs[EP_BULK_IN], 0, (*_endpoint_configs)[EP_BULK_IN].max_packet);
memset(_endpoint_buffs[EP_INT_IN], 0, (*_endpoint_configs)[EP_INT_IN].max_packet);
write_start(_endpoints[EP_BULK_IN], _endpoint_buffs[EP_BULK_IN], (*_endpoint_configs)[EP_BULK_IN].max_packet);
write_start(_endpoints[EP_INT_IN], _endpoint_buffs[EP_INT_IN], (*_endpoint_configs)[EP_INT_IN].max_packet);
}