Add USBDevice test code

Add a USB test and the class USBTester.cpp to go along with it.
pull/9768/head
Russ Butler 2018-02-07 16:36:35 -06:00
parent caace4ac61
commit f9f12766d8
4 changed files with 886 additions and 0 deletions

View File

@ -0,0 +1,349 @@
"""
mbed SDK
Copyright (c) 2018-2018 ARM Limited
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.
"""
from __future__ import print_function
from mbed_host_tests import BaseHostTest
from argparse import ArgumentParser
import time
import sys
from threading import Thread
import usb.core
from usb.util import build_request_type
from usb.util import CTRL_OUT, CTRL_IN
from usb.util import CTRL_TYPE_STANDARD, CTRL_TYPE_CLASS, CTRL_TYPE_VENDOR
from usb.util import (CTRL_RECIPIENT_DEVICE, CTRL_RECIPIENT_INTERFACE,
CTRL_RECIPIENT_ENDPOINT, CTRL_RECIPIENT_OTHER)
def get_interface(dev, interface, alternate=0):
intf = None
for active_if in dev.get_active_configuration():
if active_if.bInterfaceNumber == interface and active_if.bAlternateSetting == alternate:
assert intf is None, "duplicate interface"
intf = active_if
return intf
VENDOR_TEST_CTRL_IN = 1
VENDOR_TEST_CTRL_OUT = 2
VENDOR_TEST_CTRL_NONE = 3
VENDOR_TEST_CTRL_IN_DELAY = 4
VENDOR_TEST_CTRL_OUT_DELAY = 5
VENDOR_TEST_CTRL_NONE_DELAY = 6
VENDOR_TEST_CTRL_IN_STATUS_DELAY = 7
VENDOR_TEST_CTRL_OUT_STATUS_DELAY = 8
VENDOR_TEST_UNSUPPORTED_REQUEST = 32
class PyusbBasicTest(BaseHostTest):
"""
"""
def _callback_usb_enumeration_done(self, key, value, timestamp):
print("Received key %s = %s" % (key, value))
self.log("Received key %s = %s" % (key, value))
test_device(value, self.log)
passed = True
results = "pass" if passed else "fail"
self.send_kv(results, "0")
def setup(self):
self.__result = False
self.register_callback('usb_enumeration_done', self._callback_usb_enumeration_done)
def result(self):
return self.__result
def teardown(self):
pass
class TestMatch(object):
def __init__(self, serial):
self.serial = serial
def __call__(self, dev):
try:
return dev.serial_number == self.serial
except ValueError:
return False
def test_device(serial_number, log=print):
dev = usb.core.find(custom_match=TestMatch(serial_number))
if dev is None:
log("Device not found")
return
## --Control Tests-- ##
#control_basic_test(dev, log)
# Test control IN/OUT/NODATA
control_stall_test(dev, log)
# Invalid control in/out/nodata requests are stalled
# Stall during different points in the control transfer
#control_sizes_test(dev, log)
# Test control requests of various data stage sizes (1,8,16,32,64,255,256,...)
control_stress_test(dev, log)
# normal and delay mode
## --Endpoint test-- ##
#for each endpoint
#-test all allowed wMaxPacketSize sizes and transfer types
#-stall tests
#-set/clear stall control request
#-stall at random points of sending/receiveing data
#-test aborting an in progress transfer
#test as many endpoints at once as possible
#test biggest configuration possible
## --physical test-- ##
#-reset notification/handling
#-connect/disconnect tests - have device disconnect and then reconnect
#-disconnect during various phases of control transfers and endpoint transfers
#-suspend/resume tests (may not be possible to test with current framework)
#-suspend/resume notifications
## -- Stress tests-- ##
#-concurrent tests (all endpoints at once including control)
#-concurrent tests + reset + delay
## -- other tests-- ##
#-report throughput for in/out of control, bulk, interrupt and iso transfers
#-verify that construction/destruction repeatedly works gracefully
intf = get_interface(dev, 0, 0)
# Find endpoints
bulk_in = None
bulk_out = None
int_in = None
int_out = None
for endpoint in intf:
log("Processing endpoint %s" % endpoint)
ep_type = endpoint.bmAttributes & 0x3
if ep_type == 2:
if endpoint.bEndpointAddress & 0x80:
assert bulk_in is None
bulk_in = endpoint
else:
assert bulk_out is None
bulk_out = endpoint
elif ep_type == 3:
if endpoint.bEndpointAddress & 0x80:
assert int_in is None
int_in = endpoint
else:
assert int_out is None
int_out = endpoint
assert bulk_in is not None
assert bulk_out is not None
assert int_in is not None
assert int_out is not None
bulk_out.write("hello" + "x" *256);
int_out.write("world" + "x" *256);
dev.set_interface_altsetting(0, 1)
intf = get_interface(dev, 0, 0)
# Find endpoints
bulk_in = None
bulk_out = None
int_in = None
int_out = None
for endpoint in intf:
log("Processing endpoint %s" % endpoint)
ep_type = endpoint.bmAttributes & 0x3
if ep_type == 2:
if endpoint.bEndpointAddress & 0x80:
assert bulk_in is None
bulk_in = endpoint
else:
assert bulk_out is None
bulk_out = endpoint
elif ep_type == 3:
if endpoint.bEndpointAddress & 0x80:
assert int_in is None
int_in = endpoint
else:
assert int_out is None
int_out = endpoint
assert bulk_in is not None
assert bulk_out is not None
assert int_in is not None
assert int_out is not None
bulk_out.write("hello2" + "x" *256);
int_out.write("world2" + "x" *256);
t = Thread(target=write_data, args=(bulk_out,))
t.start()
for _ in range(10):
request_type = build_request_type(CTRL_OUT, CTRL_TYPE_VENDOR,
CTRL_RECIPIENT_DEVICE)
request = VENDOR_TEST_CTRL_NONE_DELAY
value = 0 # Always 0 for this request
index = 0 # Communication interface
length = 0 # No data
dev.ctrl_transfer(request_type, request, value, index, length, 5000)
t.join()
return True
def write_data(pipe):
print("Write data running")
count = 0
for _ in range(40):
pipe.write("Value is %s" % count)
count += 1
print("Count %s" % count)
time.sleep(0.5)
def control_stall_test(dev, log):
# Control OUT stall
try:
request_type = build_request_type(CTRL_OUT, CTRL_TYPE_VENDOR,
CTRL_RECIPIENT_DEVICE)
request = VENDOR_TEST_UNSUPPORTED_REQUEST
value = 0 # Always 0 for this request
index = 0 # Communication interface
data = bytearray(64) # Dummy data
dev.ctrl_transfer(request_type, request, value, index, data, 5000)
raise Exception("Invalid request not stalled")
except usb.core.USBError:
log("Invalid request stalled")
# Control request with no data stage (Device-to-host)
try:
request_type = build_request_type(CTRL_IN, CTRL_TYPE_VENDOR,
CTRL_RECIPIENT_DEVICE)
request = VENDOR_TEST_UNSUPPORTED_REQUEST
value = 0 # Always 0 for this request
index = 0 # Communication interface
length = 0
dev.ctrl_transfer(request_type, request, value, index, length, 5000)
raise Exception("Invalid request not stalled")
except usb.core.USBError:
log("Invalid request stalled")
# Control request with no data stage (Host-to-device)
try:
request_type = build_request_type(CTRL_OUT, CTRL_TYPE_VENDOR,
CTRL_RECIPIENT_DEVICE)
request = VENDOR_TEST_UNSUPPORTED_REQUEST
value = 0 # Always 0 for this request
index = 0 # Communication interface
length = 0
dev.ctrl_transfer(request_type, request, value, index, length, 5000)
raise Exception("Invalid request not stalled")
except usb.core.USBError:
log("Invalid request stalled")
# Control IN stall
try:
request_type = build_request_type(CTRL_IN, CTRL_TYPE_VENDOR,
CTRL_RECIPIENT_DEVICE)
request = VENDOR_TEST_UNSUPPORTED_REQUEST
value = 0 # Always 0 for this request
index = 0 # Communication interface
length = 255
dev.ctrl_transfer(request_type, request, value, index, length, 5000)
raise Exception("Invalid request not stalled")
except usb.core.USBError:
log("Invalid request stalled")
for i in (6, 7, 5):
try:
request_type = build_request_type(CTRL_IN, CTRL_TYPE_STANDARD,
CTRL_RECIPIENT_DEVICE)
request = 0x6 # GET_DESCRIPTOR
value = (0x03 << 8) | (i << 0) # String descriptor index
index = 0 # Communication interface
length = 255
resp = dev.ctrl_transfer(request_type, request, value, index, length, 5000)
log("Requesting string %s passed" % i)
except usb.core.USBError:
log("Requesting string %s failed" % i)
def control_stress_test(dev, log):
# Test various patterns of control transfers
#
# Some devices have had problems with back-to-back
# control transfers. Intentionally send these sequences
# to make sure they are properly handled.
count = 0
for _ in range(100):
# Control transfer with a data in stage
request_type = build_request_type(CTRL_IN, CTRL_TYPE_VENDOR,
CTRL_RECIPIENT_DEVICE)
request = VENDOR_TEST_CTRL_IN
value = 8 # Size of data the device should actually send
index = count # Unused - set for debugging only
length = 255
dev.ctrl_transfer(request_type, request, value, index, length, 5000)
count += 1
for _ in range(100):
# Control transfer with a data out stage followed
# by a control transfer with a data in stage
request_type = build_request_type(CTRL_OUT, CTRL_TYPE_VENDOR,
CTRL_RECIPIENT_DEVICE)
request = VENDOR_TEST_CTRL_OUT
value = 8 # Size of data the device should actually read
index = count # Unused - set for debugging only
data = bytearray(8) # Dummy data
dev.ctrl_transfer(request_type, request, value, index, data, 5000)
count += 1
request_type = build_request_type(CTRL_IN, CTRL_TYPE_VENDOR,
CTRL_RECIPIENT_DEVICE)
request = VENDOR_TEST_CTRL_IN
value = 8 # Size of data the device should actually send
index = count # Unused - set for debugging only
length = 255
dev.ctrl_transfer(request_type, request, value, index, length, 5000)
count += 1
for _ in range(100):
# Control transfer with a data out stage
request_type = build_request_type(CTRL_OUT, CTRL_TYPE_VENDOR,
CTRL_RECIPIENT_DEVICE)
request = VENDOR_TEST_CTRL_OUT
value = 8 # Size of data the device should actually read
index = count # Unused - set for debugging only
data = bytearray(8) # Dummy data
dev.ctrl_transfer(request_type, request, value, index, data, 5000)
count += 1
def main():
parser = ArgumentParser(description="USB basic test")
parser.add_argument('serial', help='USB serial number of DUT')
args = parser.parse_args()
ret = test_device(args.serial)
print("Test %s" % "passed" if ret else "failed")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,384 @@
/*
* 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 "USBTester.h"
#include "mbed_shared_queues.h"
#include "EndpointResolver.h"
#define DEFAULT_CONFIGURATION (1)
#define VENDOR_TEST_CTRL_IN 1
#define VENDOR_TEST_CTRL_OUT 2
#define VENDOR_TEST_CTRL_NONE 3
#define VENDOR_TEST_CTRL_IN_DELAY 4
#define VENDOR_TEST_CTRL_OUT_DELAY 5
#define VENDOR_TEST_CTRL_NONE_DELAY 6
#define VENDOR_TEST_CTRL_IN_STATUS_DELAY 7
#define VENDOR_TEST_CTRL_OUT_STATUS_DELAY 8
#define MAX_EP_SIZE 64
#define MIN_EP_SIZE 8
USBTester::USBTester(uint16_t vendor_id, uint16_t product_id, uint16_t product_release, bool connect_blocking): USBDevice(vendor_id, product_id, product_release)
{
EndpointResolver resolver(endpoint_table());
resolver.endpoint_ctrl(64);
bulk_in = resolver.endpoint_in(USB_EP_TYPE_BULK, 64);
bulk_out = resolver.endpoint_out(USB_EP_TYPE_BULK, 64);
int_in = resolver.endpoint_in(USB_EP_TYPE_INT, 64);
int_out = resolver.endpoint_out(USB_EP_TYPE_INT, 64);
MBED_ASSERT(resolver.valid());
queue = mbed_highprio_event_queue();
configuration_desc();
init();
USBDevice::connect(connect_blocking);
}
USBTester::~USBTester()
{
deinit();
}
void USBTester::callback_state_change(DeviceState new_state)
{
// Nothing to do
};
void USBTester::callback_request(const setup_packet_t *setup)
{
/* Called in ISR context */
RequestResult result = PassThrough;
uint8_t *data = NULL;
uint32_t size = 0;
uint32_t delay = 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_NONE:
result = Success;
break;
case VENDOR_TEST_CTRL_NONE_DELAY:
result = Success;
delay = 2000;
break;
default:
result = PassThrough;
break;
}
}
if (delay) {
queue->call_in(delay, static_cast<USBDevice *>(this), &USBTester::complete_request, Success, data, size);
} else {
complete_request(result, data, size);
}
}
void USBTester::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;
default:
result = false;
break;
}
}
complete_request_xfer_done(true);
}
// Called in ISR context
// Set configuration. Return false if the
// configuration is not supported.
void USBTester::callback_set_configuration(uint8_t configuration)
{
if (configuration != DEFAULT_CONFIGURATION) {
complete_set_configuration(false);
return;
}
// Configure endpoints > 0
endpoint_add(int_in, MAX_EP_SIZE, USB_EP_TYPE_INT);
endpoint_add(int_out, MAX_EP_SIZE, USB_EP_TYPE_INT, &USBTester::epint_out_callback);
endpoint_add(bulk_in, MAX_EP_SIZE, USB_EP_TYPE_BULK);
endpoint_add(bulk_out, MAX_EP_SIZE, USB_EP_TYPE_BULK, &USBTester::epbulk_out_callback);
read_start(int_out);
read_start(bulk_out);
complete_set_configuration(true);
}
void USBTester::callback_set_interface(uint16_t interface, uint8_t alternate)
{
if (interface == 0 && alternate == 0) {
endpoint_remove(int_in);
endpoint_remove(int_out);
endpoint_remove(bulk_in);
endpoint_remove(bulk_out);
endpoint_add(int_in, MAX_EP_SIZE, USB_EP_TYPE_INT);
endpoint_add(int_out, MAX_EP_SIZE, USB_EP_TYPE_INT, &USBTester::epint_out_callback);
endpoint_add(bulk_in, MAX_EP_SIZE, USB_EP_TYPE_BULK);
endpoint_add(bulk_out, MAX_EP_SIZE, USB_EP_TYPE_BULK, &USBTester::epbulk_out_callback);
read_start(int_out);
read_start(bulk_out);
complete_set_interface(true);
return;
}
if (interface == 0 && alternate == 1) {
endpoint_remove(int_in);
endpoint_remove(int_out);
endpoint_remove(bulk_in);
endpoint_remove(bulk_out);
endpoint_add(int_in, MIN_EP_SIZE, USB_EP_TYPE_INT);
endpoint_add(int_out, MIN_EP_SIZE, USB_EP_TYPE_INT, &USBTester::epint_out_callback);
endpoint_add(bulk_in, MIN_EP_SIZE, USB_EP_TYPE_BULK);
endpoint_add(bulk_out, MIN_EP_SIZE, USB_EP_TYPE_BULK, &USBTester::epbulk_out_callback);
read_start(int_out);
read_start(bulk_out);
complete_set_interface(true);
return;
}
complete_set_interface(false);
}
const uint8_t *USBTester::device_desc()
{
uint8_t ep0_size = endpoint_max_packet_size(0x00);
uint8_t device_descriptor_temp[] = {
18, // bLength
1, // bDescriptorType
0x10, 0x01, // bcdUSB
0, // bDeviceClass
0, // bDeviceSubClass
0, // bDeviceProtocol
ep0_size, // bMaxPacketSize0
(uint8_t)(LSB(vendor_id)), (uint8_t)(MSB(vendor_id)), // idVendor
(uint8_t)(LSB(product_id)), (uint8_t)(MSB(product_id)),// idProduct
0x00, 0x01, // bcdDevice
1, // iManufacturer
2, // iProduct
3, // iSerialNumber
1 // bNumConfigurations
};
MBED_ASSERT(sizeof(device_descriptor_temp) == sizeof(device_descriptor));
memcpy(device_descriptor, device_descriptor_temp, sizeof(device_descriptor));
return device_descriptor;
}
const uint8_t *USBTester::string_iinterface_desc()
{
static const uint8_t string_iinterface_descriptor[] = {
0x08,
STRING_DESCRIPTOR,
'C', 0, 'D', 0, 'C', 0,
};
return string_iinterface_descriptor;
}
const uint8_t *USBTester::string_iproduct_desc()
{
static const uint8_t string_iproduct_descriptor[] = {
0x16,
STRING_DESCRIPTOR,
'C', 0, 'D', 0, 'C', 0, ' ', 0, 'D', 0, 'E', 0, 'V', 0, 'I', 0, 'C', 0, 'E', 0
};
return string_iproduct_descriptor;
}
#define CONFIG1_DESC_SIZE (9+9+7+7+7+7 + 9+7+7+7+7)
const uint8_t *USBTester::configuration_desc()
{
static const uint8_t config_descriptor[] = {
// configuration descriptor
9, // bLength
2, // bDescriptorType
LSB(CONFIG1_DESC_SIZE), // wTotalLength
MSB(CONFIG1_DESC_SIZE),
1, // bNumInterfaces
1, // bConfigurationValue
0, // iConfiguration
0x80, // bmAttributes
50, // bMaxPower
// Interface 0 setting 0
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
0, // bInterfaceNumber
0, // bAlternateSetting
4, // 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
bulk_in, // bEndpointAddress
E_BULK, // bmAttributes (0x02=bulk)
LSB(MAX_EP_SIZE),// wMaxPacketSize (LSB)
MSB(MAX_EP_SIZE),// wMaxPacketSize (MSB)
0, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
bulk_out, // bEndpointAddress
E_BULK, // bmAttributes (0x02=bulk)
LSB(MAX_EP_SIZE),// wMaxPacketSize (LSB)
MSB(MAX_EP_SIZE),// wMaxPacketSize (MSB)
0, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
int_in, // bEndpointAddress
E_INTERRUPT, // bmAttributes (0x03=interrupt)
LSB(MAX_EP_SIZE), // wMaxPacketSize (LSB)
MSB(MAX_EP_SIZE), // wMaxPacketSize (MSB)
1, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
int_out, // bEndpointAddress
E_INTERRUPT, // bmAttributes (0x03=interrupt)
LSB(MAX_EP_SIZE), // wMaxPacketSize (LSB)
MSB(MAX_EP_SIZE), // wMaxPacketSize (MSB)
1, // bInterval
// Interface 0 setting 1
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
0, // bInterfaceNumber
1, // bAlternateSetting
4, // 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
bulk_in, // bEndpointAddress
E_BULK, // bmAttributes (0x02=bulk)
LSB(MIN_EP_SIZE), // wMaxPacketSize (LSB)
MSB(MIN_EP_SIZE), // wMaxPacketSize (MSB)
0, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
bulk_out, // bEndpointAddress
E_BULK, // bmAttributes (0x02=bulk)
LSB(MIN_EP_SIZE), // wMaxPacketSize (LSB)
MSB(MIN_EP_SIZE), // wMaxPacketSize (MSB)
0, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
int_in, // bEndpointAddress
E_INTERRUPT, // bmAttributes (0x03=interrupt)
LSB(MIN_EP_SIZE), // wMaxPacketSize (LSB)
MSB(MIN_EP_SIZE), // wMaxPacketSize (MSB)
1, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ENDPOINT_DESCRIPTOR, // bDescriptorType
int_out, // bEndpointAddress
E_INTERRUPT, // bmAttributes (0x03=interrupt)
LSB(MIN_EP_SIZE), // wMaxPacketSize (LSB)
MSB(MIN_EP_SIZE), // wMaxPacketSize (MSB)
1 // bInterval
};
return config_descriptor;
}
void USBTester::epint_out_callback(usb_ep_t endpoint)
{
uint8_t buffer[65];
uint32_t size = 0;
if (!read_finish(endpoint, buffer, sizeof(buffer), &size)) {
return;
}
if (!read_start(endpoint)) {
return;
}
}
void USBTester::epbulk_out_callback(usb_ep_t endpoint)
{
uint8_t buffer[65];
uint32_t size = 0;
if (!read_finish(endpoint, buffer, sizeof(buffer), &size)) {
return;
}
if (!read_start(endpoint)) {
return;
}
}

View File

@ -0,0 +1,91 @@
/*
* 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.
*/
#ifndef USB_TESTER_H
#define USB_TESTER_H
/* These headers are included for child class. */
#include "USBDescriptor.h"
#include "USBDevice_Types.h"
#include "EventQueue.h"
#include "USBDevice.h"
class USBTester: public USBDevice {
public:
/*
* Constructor
*
* @param vendor_id Your vendor_id
* @param product_id Your product_id
* @param product_release Your preoduct_release
* @param connect_blocking define if the connection must be blocked if USB not plugged in
*/
USBTester(uint16_t vendor_id, uint16_t product_id, uint16_t product_release, bool connect_blocking);
~USBTester();
protected:
/*
* Get device descriptor. Warning: this method has to store the length of the report descriptor in reportLength.
*
* @returns pointer to the device descriptor
*/
virtual const uint8_t *device_desc();
/*
* Get string product descriptor
*
* @returns pointer to the string product descriptor
*/
virtual const uint8_t *string_iproduct_desc();
/*
* Get string interface descriptor
*
* @returns pointer to the string interface descriptor
*/
virtual const uint8_t *string_iinterface_desc();
/*
* Get configuration descriptor
*
* @returns pointer to the configuration descriptor
*/
virtual const uint8_t *configuration_desc();
protected:
uint8_t bulk_in;
uint8_t bulk_out;
uint8_t int_in;
uint8_t int_out;
EventQueue *queue;
virtual void callback_state_change(DeviceState new_state);
virtual void callback_request(const setup_packet_t *setup);
virtual void callback_request_xfer_done(const setup_packet_t *setup, bool aborted);
virtual void callback_set_configuration(uint8_t configuration);
virtual void callback_set_interface(uint16_t interface, uint8_t alternate);
virtual void epbulk_out_callback(usb_ep_t endpoint);
virtual void epint_out_callback(usb_ep_t endpoint);
uint8_t ctrl_buf[2048];
};
#endif

View File

@ -0,0 +1,62 @@
/*
* 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 <stdio.h>
#include <string.h>
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest/utest.h"
#include "USBTester.h"
#if !defined(DEVICE_USBDEVICE) || !DEVICE_USBDEVICE
#error [NOT_SUPPORTED] USB Device not supported for this target
#endif
using namespace utest::v1;
// Echo server (echo payload to host)
void test_case_basic()
{
char _key[11] = {};
char _value[128] = {};
{
USBTester serial(0x0d28, 0x0205, 0x0001, true);
greentea_send_kv("usb_enumeration_done", "0123456789");
// Wait for host before terminating
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
}
}
Case cases[] = {
Case("pyusb basic test", test_case_basic),
};
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(120, "pyusb_basic");
return greentea_test_setup_handler(number_of_cases);
}
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
int main()
{
Harness::run(specification);
}