1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-25 14:33:52 +01:00

tests/usbus: Add automated test for usbus init

This commit is contained in:
Koen Zandberg 2019-09-17 22:10:29 +02:00
parent 5b477918b6
commit e3123f352e
No known key found for this signature in database
GPG Key ID: 0895A893E6D2985B
5 changed files with 742 additions and 0 deletions

23
tests/usbus/Makefile Normal file
View File

@ -0,0 +1,23 @@
include ../Makefile.tests_common
USEMODULE += embunit
USEMODULE += usbus
FEATURES_PROVIDED += periph_usbdev
# USB device vendor and product ID
DEFAULT_VID = 1209
DEFAULT_PID = 0001
USB_VID ?= $(DEFAULT_VID)
USB_PID ?= $(DEFAULT_PID)
CFLAGS += -DUSB_CONFIG_VID=0x$(USB_VID) -DUSB_CONFIG_PID=0x$(USB_PID)
include $(RIOTBASE)/Makefile.include
.PHONY: usb_id_check
usb_id_check:
@if [ $(USB_VID) = $(DEFAULT_VID) ] || [ $(USB_PID) = $(DEFAULT_PID) ] ; then \
$(COLOR_ECHO) "$(COLOR_RED)Private testing pid.codes USB VID/PID used!, do not use it outside of test environments!$(COLOR_RESET)" 1>&2 ; \
$(COLOR_ECHO) "$(COLOR_RED)MUST NOT be used on any device redistributed, sold or manufactured, VID/PID is not unique!$(COLOR_RESET)" 1>&2 ; \
fi
all: | usb_id_check

354
tests/usbus/main.c Normal file
View File

@ -0,0 +1,354 @@
/*
* Copyright (C) 2019 Koen Zandberg <koen@bergzand.net>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief Tests USB interaction with USBUS
*
* @author Koen Zandberg <koen@bergzand.net>
*
* @}
*/
#include <string.h>
#include <errno.h>
#include "mutex.h"
#include "periph/usbdev.h"
#include "embUnit.h"
#include "usbdev_mock.h"
#include "usb/descriptor.h"
#include "usb/usbus.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/**
* @brief Test case states
*/
typedef enum {
TESTPHASE_START, /**< Initial start */
TESTPHASE_RESET, /**< Signal USB RESET */
TESTPHASE_REQ_DEV_INIT, /**< Request the first part of the device descriptor */
TESTPHASE_RESET2, /**< Second reset */
TESTPHASE_SET_ADDRESS, /**< Configure Address */
TESTPHASE_REQ_DEV_FULL, /**< Request the full device descriptor */
TESTPHASE_FINAL, /**< Testing done */
} testphase_t;
/**
* @brief Test control request phases
*/
typedef enum {
TEST_REQ_PHASE_IDLE,
TEST_REQ_PHASE_START_GET,
TEST_REQ_PHASE_START_SET,
TEST_REQ_PHASE_OUTDATA,
TEST_REQ_PHASE_INDATA,
TEST_REQ_PHASE_OUTACK,
TEST_REQ_PHASE_INACK,
} test_req_phase_t;
testphase_t phase = TESTPHASE_START;
test_req_phase_t req_phase = TEST_REQ_PHASE_IDLE;
static usbus_t usbus;
static char _stack[USBUS_STACKSIZE];
static mutex_t waiter = MUTEX_INIT;
static char *_state2str(test_req_phase_t state)
{
switch (state) {
case TEST_REQ_PHASE_IDLE:
return "idle";
case TEST_REQ_PHASE_START_GET:
return "start get";
case TEST_REQ_PHASE_START_SET:
return "start set";
case TEST_REQ_PHASE_OUTDATA:
return "OUT data";
case TEST_REQ_PHASE_INDATA:
return "IN data";
case TEST_REQ_PHASE_OUTACK:
return "OUT Ack";
case TEST_REQ_PHASE_INACK:
return "IN Ack";
}
return "unknown control request state";
}
static void _build_conf_req(uint8_t *buf, size_t reqlen)
{
usb_setup_t *setup = (usb_setup_t *)buf;
memset(setup, 0, sizeof(usb_setup_t));
setup->type = USB_SETUP_REQUEST_DEVICE2HOST;
setup->request = USB_SETUP_REQ_GET_DESCRIPTOR;
setup->value = USB_TYPE_DESCRIPTOR_DEVICE << 8;
setup->length = reqlen;
}
static void _build_set_addr(uint8_t *buf)
{
usb_setup_t *setup = (usb_setup_t *)buf;
memset(setup, 0, sizeof(usb_setup_t));
setup->request = USB_SETUP_REQ_SET_ADDRESS;
setup->value = 42;
}
static void _start_setup_get(usbdev_mock_t *dev)
{
req_phase = TEST_REQ_PHASE_START_GET;
dev->in[0].available = 0;
/* Trigger the OUT request at the USBUS stack */
dev->usbdev.epcb(&dev->out[0].ep, USBDEV_EVENT_ESR);
}
static void _start_setup_set(usbdev_mock_t *dev)
{
req_phase = TEST_REQ_PHASE_START_SET;
dev->in[0].available = 0;
dev->usbdev.epcb(&dev->out[0].ep, USBDEV_EVENT_ESR);
}
/* Validates the first 8 bytes of the device descriptor */
static void _validate_device_desc_init(usb_descriptor_device_t *desc)
{
TEST_ASSERT_EQUAL_INT(sizeof(usb_descriptor_device_t), desc->length);
TEST_ASSERT_EQUAL_INT(USB_TYPE_DESCRIPTOR_DEVICE, desc->type);
}
static void _test_sequence(usbdev_mock_t *dev)
{
testphase_t next_phase = TESTPHASE_FINAL;
/* Global sequence control */
/* Called as part of the ESR handling */
switch (phase) {
case TESTPHASE_START:
next_phase = TESTPHASE_RESET;
/* Signal reset condition */
DEBUG("[test]: Signalling USB reset condition\n");
dev->usbdev.cb(&dev->usbdev, USBDEV_EVENT_RESET);
dev->usbdev.cb(&dev->usbdev, USBDEV_EVENT_ESR);
break;
case TESTPHASE_RESET:
next_phase = TESTPHASE_REQ_DEV_INIT;
DEBUG("[test]: Requesting device descriptor\n");
_build_conf_req(dev->out[0].ep.buf, 8); /* initial config request */
dev->req_len = 8;
dev->out[0].state = EP_STATE_DATA_AVAILABLE;
dev->out[0].available = 8;
_start_setup_get(dev);
break;
case TESTPHASE_REQ_DEV_INIT:
next_phase = TESTPHASE_RESET2;
DEBUG("[test]: validating device descriptor\n");
TEST_ASSERT_EQUAL_INT(dev->in[0].available, 8);
_validate_device_desc_init(
(usb_descriptor_device_t *)dev->in[0].buf_start);
/* Reset device */
DEBUG("[test]: Signalling second USB reset condition\n");
dev->usbdev.cb(&dev->usbdev, USBDEV_EVENT_RESET);
dev->usbdev.cb(&dev->usbdev, USBDEV_EVENT_ESR);
break;
case TESTPHASE_RESET2:
next_phase = TESTPHASE_SET_ADDRESS;
DEBUG("[test]: Set USB address\n");
_build_set_addr(dev->out[0].ep.buf);
dev->req_len = 0;
dev->out[0].state = EP_STATE_DATA_AVAILABLE;
dev->out[0].available = 8;
_start_setup_set(dev);
break;
case TESTPHASE_SET_ADDRESS:
next_phase = TESTPHASE_REQ_DEV_FULL;
DEBUG("[test]: Requesting full device descriptor\n");
_build_conf_req(dev->out[0].ep.buf,
sizeof(usb_descriptor_device_t)); /* initial config request */
dev->req_len = sizeof(usb_descriptor_device_t);
dev->out[0].state = EP_STATE_DATA_AVAILABLE;
dev->out[0].available = sizeof(usb_setup_t);
_start_setup_get(dev);
break;
case TESTPHASE_REQ_DEV_FULL:
TEST_ASSERT_EQUAL_INT(dev->in[0].available,
sizeof(usb_descriptor_device_t));
DEBUG("[test]: Validating full descriptor\n");
_validate_device_desc_init(
(usb_descriptor_device_t *)dev->in[0].buf_start);
next_phase = TESTPHASE_FINAL;
dev->usbdev.cb(&dev->usbdev, USBDEV_EVENT_ESR);
break;
case TESTPHASE_FINAL:
/* Testing done */
mutex_unlock(&waiter);
break;
default:
DEBUG("[test]: Unhandled situation in test script\n");
}
phase = next_phase;
}
/* Validates the ready call after submitting a setup request */
static void _validate_get_req_start(usbdev_mock_ep_t *ep)
{
DEBUG("[validation]: get request validation\n");
/* We should get an IN request with the data */
TEST_ASSERT_EQUAL_INT(ep->ep.dir, USB_EP_DIR_IN);
req_phase = TEST_REQ_PHASE_INDATA;
}
static void _validate_out_ack(usbdev_mock_t *dev, usbdev_mock_ep_t *ep)
{
DEBUG("[validation]: OUT ACK validation\n");
TEST_ASSERT_EQUAL_INT(ep->ep.dir, USB_EP_DIR_OUT);
dev->usbdev.epcb(&dev->out[0].ep, USBDEV_EVENT_ESR);
req_phase = TEST_REQ_PHASE_IDLE;
}
static void _validate_in_ack(usbdev_mock_t *dev, usbdev_mock_ep_t *ep,
size_t len)
{
DEBUG("[validation]: IN ACK validation\n");
TEST_ASSERT_EQUAL_INT(ep->ep.dir, USB_EP_DIR_IN);
TEST_ASSERT_EQUAL_INT(len, 0);
dev->usbdev.epcb(&dev->in[0].ep, USBDEV_EVENT_ESR);
req_phase = TEST_REQ_PHASE_IDLE;
}
static void _validate_set_req_start(usbdev_mock_t *dev, usbdev_mock_ep_t *ep,
size_t len)
{
DEBUG("[validation]: set request validation\n");
TEST_ASSERT_EQUAL_INT(dev->out[0].available, 8);
/* We should get an IN request with the data */
TEST_ASSERT_EQUAL_INT(ep->ep.dir, USB_EP_DIR_IN);
if (dev->req_len == 0) {
DEBUG("[validation]: No payload, performing IN ACK validation\n");
/* No data phase, this `ready` is the OUT ACK */
_validate_in_ack(dev, ep, len);
}
else {
req_phase = TEST_REQ_PHASE_OUTDATA;
}
}
static void _handle_data(usbdev_mock_t *dev, usbdev_mock_ep_t *ep, size_t len)
{
if (ep->ep.dir == USB_EP_DIR_IN) {
/* Zero length IN packet is not valid here */
DEBUG("[data]: Handling IN data from stack: %u\n", (unsigned)len);
TEST_ASSERT(len != 0);
dev->usbdev.epcb(&dev->in[0].ep, USBDEV_EVENT_ESR);
if (ep->available == dev->req_len) {
DEBUG("[data]: Full data received from stack\n");
req_phase = TEST_REQ_PHASE_OUTACK;
/* Reset buffer ptr to the start */
ep->ep.buf = ep->buf_start;
}
else {
DEBUG("[data]: Expecting more data from stack: %u/%u\n",
(unsigned)ep->available,
(unsigned)dev->req_len);
}
}
}
static void _ep_esr_validation(usbdev_mock_t *dev, usbdev_mock_ep_t *ep)
{
DEBUG("[ep esr]: Data available for stack: %u\n", ep->available);
if (req_phase == TEST_REQ_PHASE_IDLE) {
DEBUG("[ep esr]: Done with the request\n");
/* signal USBDEV_EVENT_ESR to call _test_sequence */
dev->usbdev.cb(&dev->usbdev, USBDEV_EVENT_ESR);
}
ep->ep.dev->epcb(&ep->ep, USBDEV_EVENT_TR_COMPLETE);
}
/* Handles Control endpoint validation from the usbdev side. *
* Called as part of the endpoint ready function. */
static void _ep0_validation(usbdev_mock_t *dev, usbdev_mock_ep_t *ep,
size_t len)
{
DEBUG("[validation]: req state: %s\n", _state2str(req_phase));
/* Validate direction and content for the current state */
switch (req_phase) {
case TEST_REQ_PHASE_START_GET:
_validate_get_req_start(ep);
_handle_data(dev, ep, len);
break;
case TEST_REQ_PHASE_START_SET:
_validate_set_req_start(dev, ep, len);
break;
case TEST_REQ_PHASE_OUTACK:
_validate_out_ack(dev, ep);
break;
case TEST_REQ_PHASE_INACK:
_validate_in_ack(dev, ep, len);
break;
default:
/* Nothing is validated at the moment for the cases of:
* - TEST_REQ_PHASE_IDLE
* - TEST_REQ_PHASE_INDATA
* - TEST_REQ_PHASE_OUTDATA
*/
break;
}
}
static void _setup(void)
{
mutex_lock(&waiter);
}
static void _test(void)
{
_setup();
/* Initialize basic usbus struct, don't start the thread yet */
usbdev_t *usbdev = usbdev_get_ctx(0);
usbus_init(&usbus, usbdev);
usbdev_mock_setup(&_test_sequence, &_ep_esr_validation, &_ep0_validation);
usbus_create(_stack, USBUS_STACKSIZE, USBUS_PRIO, USBUS_TNAME, &usbus);
/* Try to lock to block until the test thread has finished */
mutex_lock(&waiter);
}
static Test *tests_usbus(void)
{
EMB_UNIT_TESTFIXTURES(fixtures) {
new_TestFixture(_test),
};
EMB_UNIT_TESTCALLER(tests, NULL, NULL, fixtures);
return (Test *)&tests;
}
int main(void)
{
TESTS_START();
TESTS_RUN(tests_usbus());
TESTS_END();
return 0;
}

22
tests/usbus/tests/01-run.py Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env python3
# Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
# Copyright (C) 2016 Takuo Yonezawa <Yonezawa-T2@mail.dnp.co.jp>
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
import os
import sys
def testfunc(child):
child.expect(r"OK \(1 tests\)")
if __name__ == "__main__":
sys.path.append(os.path.join(os.environ['RIOTBASE'],
'dist/tools/testrunner'))
from testrunner import run
sys.exit(run(testfunc))

226
tests/usbus/usbdev_mock.c Normal file
View File

@ -0,0 +1,226 @@
/*
* Copyright (C) 2019 Koen Zandberg <koen@bergzand.net>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
*
* @file
* @author Koen Zandberg <koen@bergzand.net>
*/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "embUnit.h"
#include "periph/usbdev.h"
#include "usbdev_mock.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static usbdev_mock_t usbdev_mock;
static uint8_t _in_buf[256]; /* "host" in */
static uint8_t _out_buf[64]; /* "host" out */
static const usbdev_driver_t testdriver;
static usbdev_mock_t *_ep2dev(usbdev_ep_t *ep)
{
return (usbdev_mock_t *)ep->dev;
}
void usbdev_init_lowlevel(void)
{
}
usbdev_t *usbdev_get_ctx(unsigned num)
{
(void)num;
return &usbdev_mock.usbdev;
}
void usbdev_mock_setup(usbdev_mock_esr_cb_t esr_cb,
usbdev_mock_ep_esr_cb_t ep_esr_cb,
usbdev_mock_ready_cb_t ready_cb)
{
memset(&usbdev_mock, 0, sizeof(usbdev_mock));
usbdev_mock.usbdev.driver = &testdriver;
usbdev_mock.esr_cb = esr_cb;
usbdev_mock.ep_esr_cb = ep_esr_cb;
usbdev_mock.ready_cb = ready_cb;
}
static void _init(usbdev_t *usbdev)
{
usbdev_mock_t *dev = (usbdev_mock_t *)usbdev;
/* Throw first event to start the test sequence */
dev->usbdev.cb(usbdev, USBDEV_EVENT_ESR);
}
usbdev_ep_t *_new_ep(usbdev_t *dev, usb_ep_type_t type, usb_ep_dir_t dir,
size_t buf_len)
{
usbdev_mock_t *testdev = (usbdev_mock_t *)dev;
usbdev_mock_ep_t *res = NULL;
if (type == USB_EP_TYPE_CONTROL) {
if (dir == USB_EP_DIR_OUT) {
res = &testdev->out[0];
res->ep.num = 0;
res->ep.buf = _out_buf;
}
else {
res = &testdev->in[0];
res->ep.num = 0;
res->ep.buf = _in_buf;
}
}
if (res) {
res->buf_start = res->ep.buf;
res->state = EP_STATE_READY;
res->available = 0;
res->ep.len = buf_len;
res->ep.dir = dir;
res->ep.type = type;
res->ep.dev = dev;
}
return &res->ep;
}
int _get(usbdev_t *usbdev, usbopt_t opt,
void *value, size_t max_len)
{
(void)usbdev;
(void)opt;
(void)value;
(void)max_len;
DEBUG("[mock]: Unhandled get call: 0x%x\n", opt);
return -ENOTSUP;
}
int _set(usbdev_t *usbdev, usbopt_t opt,
const void *value, size_t value_len)
{
usbdev_mock_t *testdev = (usbdev_mock_t *)usbdev;
(void)value_len;
int res = -ENOTSUP;
switch (opt) {
case USBOPT_ADDRESS:
testdev->config_addr = *(uint8_t *)value;
res = sizeof(uint8_t);
break;
case USBOPT_ATTACH:
assert(value_len == sizeof(usbopt_enable_t));
res = sizeof(usbopt_enable_t);
break;
default:
DEBUG("[mock]: Unhandled set call: 0x%x\n", opt);
break;
}
return res;
}
static void _esr(usbdev_t *dev)
{
usbdev_mock_t *usbdev_mock = (usbdev_mock_t *)dev;
usbdev_mock->esr_cb(usbdev_mock);
}
void _ep_init(usbdev_ep_t *ep)
{
(void)ep;
}
int _ep_get(usbdev_ep_t *ep, usbopt_ep_t opt,
void *value, size_t max_len)
{
usbdev_mock_ep_t *testep = (usbdev_mock_ep_t *)ep;
(void)max_len;
switch (opt) {
case USBOPT_EP_AVAILABLE:
*((size_t *)value) = testep->available;
return sizeof(size_t);
default:
DEBUG("[mock]: Unhandled endpoint get call: 0x%x\n", opt);
break;
}
return -ENOTSUP;
}
int _ep_set(usbdev_ep_t *ep, usbopt_ep_t opt,
const void *value, size_t value_len)
{
(void)ep;
(void)value;
(void)value_len;
int res = -ENOTSUP;
switch (opt) {
case USBOPT_EP_ENABLE:
res = sizeof(usbopt_enable_t);
break;
case USBOPT_EP_STALL:
res = sizeof(usbopt_enable_t);
break;
default:
DEBUG("[mock]: Unhandled ep set call: 0x%x\n", opt);
break;
}
return res;
}
void _ep_esr(usbdev_ep_t *ep)
{
usbdev_mock_t *dev = _ep2dev(ep);
DEBUG("[mock]: ESR EP %u, dir %s\n",
ep->num, ep->dir == USB_EP_DIR_OUT ? "out" : "in");
usbdev_mock_ep_t *mock_ep = (usbdev_mock_ep_t *)ep;
if (mock_ep->state == EP_STATE_DATA_AVAILABLE) {
dev->ep_esr_cb(dev, mock_ep);
mock_ep->state = EP_STATE_READY;
}
}
int _ready(usbdev_ep_t *ep, size_t len)
{
DEBUG("[mock]: Readying EP %u, dir %s, len %u\n",
ep->num, ep->dir == USB_EP_DIR_OUT ? "out" : "in", (unsigned)len);
if (ep->num == 0) {
usbdev_mock_t *usbdev_mock = _ep2dev(ep);
usbdev_mock_ep_t *mock_ep = (usbdev_mock_ep_t *)ep;
mock_ep->available = len;
mock_ep->ep.buf += len;
mock_ep->state = EP_STATE_DATA_AVAILABLE;
usbdev_mock->ready_cb(usbdev_mock, (usbdev_mock_ep_t *)ep, len);
}
return 0;
}
static const usbdev_driver_t testdriver = {
.init = _init,
.new_ep = _new_ep,
.get = _get,
.set = _set,
.esr = _esr,
.ep_init = _ep_init,
.ep_get = _ep_get,
.ep_set = _ep_set,
.ep_esr = _ep_esr,
.ready = _ready,
};

117
tests/usbus/usbdev_mock.h Normal file
View File

@ -0,0 +1,117 @@
/*
* Copyright (C) 2019 Koen Zandberg <koen@bergzand.net>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup tests_usbdev_mock USBdev mockup device
* @ingroup tests
* @brief USBdev mockup device for testing
* @{
*
* @file
*
* @author Koen Zandberg <koen@bergzand.net>
*/
#ifndef USBDEV_MOCK_H
#define USBDEV_MOCK_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Number of IN and OUT endpoints available in the mock usbdev device
*/
#define USBDEV_MOCK_NUM_EP (1)
/**
* @name usbdev mock device endpoint states
*/
typedef enum {
EP_STATE_READY, /**< Endpoint is ready/idle */
EP_STATE_DATA_AVAILABLE, /**< Endpoint has data */
} usbdev_mock_ep_state_t;
/**
* @brief usbdev mock device endpoint
*/
typedef struct {
usbdev_ep_t ep; /**< Generic endpoint struct */
usbdev_mock_ep_state_t state; /**< Endpoint state */
size_t available; /**< Bytes available in the buffer */
uint8_t *buf_start; /**< Start location of the buffer */
} usbdev_mock_ep_t;
/**
* @brief usbdev mock device forward declaration
*/
typedef struct usbdev_mock usbdev_mock_t;
/**
* @brief usbdev mock device callback for esr event checking
*
* @param dev usbdev mock device descriptor
*/
typedef void (*usbdev_mock_esr_cb_t)(usbdev_mock_t *dev);
/**
* @brief usbdev mock device callback for endpoint event checking
*
* @param dev usbdev mock device descriptor
* @param ep usbdev mock device endpoint
*/
typedef void (*usbdev_mock_ep_esr_cb_t)(usbdev_mock_t *dev,
usbdev_mock_ep_t *ep);
/**
* @brief usbdev mock device callback for endpoint ready call checking
*
* @param dev usbdev mock device descriptor
* @param ep usbdev mock device endpoint
* @param len length supplied to the ready call
*/
typedef void (*usbdev_mock_ready_cb_t)(usbdev_mock_t *dev,
usbdev_mock_ep_t *ep,
size_t len);
/**
* @brief usbdev mock device
*/
struct usbdev_mock {
usbdev_t usbdev; /**< Generic usbdev device */
usbdev_mock_ep_t in[USBDEV_MOCK_NUM_EP]; /**< IN endpoints */
usbdev_mock_ep_t out[USBDEV_MOCK_NUM_EP]; /**< OUT endpoints */
uint8_t config_addr; /**< Configured address */
size_t req_len; /**< Length of the current
* request */
usbdev_mock_esr_cb_t esr_cb; /**< ESR callback for
* validation */
usbdev_mock_ep_esr_cb_t ep_esr_cb; /**< Endpoint ESR cb for
* validation */
usbdev_mock_ready_cb_t ready_cb; /**< Endpoint ready cb for
* validation */
};
/**
* @brief usbdev mock device setup function
*
* @param esr_cb ESR callback
* @param ep_esr_cb Endpoint ESR callback
* @param ready_cb Endpoint ready callback
*/
void usbdev_mock_setup(usbdev_mock_esr_cb_t esr_cb,
usbdev_mock_ep_esr_cb_t ep_esr_cb,
usbdev_mock_ready_cb_t ready_cb);
#ifdef __cplusplus
}
#endif
#endif /* USBDEV_MOCK_H */
/** @} */