Newer
Older
mbed-os / drivers / usb / tests / TESTS / usb_device / basic / USBEndpointTester.cpp
/*
 * Copyright (c) 2018-2020, 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.
 */

#if DEVICE_USBDEVICE

#include "stdint.h"
#include "stdlib.h"
#include "USBEndpointTester.h"
#include "events/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       3
#define VENDOR_TEST_CTRL_OUT_SIZES      4
#define VENDOR_TEST_RW_RESTART          5
#define VENDOR_TEST_ABORT_BUFF_CHECK    6

#define CTRL_BUF_SIZE (2048)

#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());
    configuration_desc(0);
    ctrl_buf = new uint8_t[CTRL_BUF_SIZE];
    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();
    delete[] ctrl_buf;
}

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 < CTRL_BUF_SIZE ? setup->wValue : CTRL_BUF_SIZE;
                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);
}

#endif //USB_DEVICE_TESTS