Initial project setup
This commit is contained in:
209
managed_components/espressif__tinyusb/test/fuzz/dcd_fuzz.cc
Normal file
209
managed_components/espressif__tinyusb/test/fuzz/dcd_fuzz.cc
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Nathaniel Brough
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include "device/dcd.h"
|
||||
#include "fuzz/fuzz_private.h"
|
||||
#include <assert.h>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// State tracker
|
||||
//--------------------------------------------------------------------+
|
||||
struct State {
|
||||
bool interrupts_enabled;
|
||||
bool sof_enabled;
|
||||
uint8_t address;
|
||||
};
|
||||
|
||||
tu_static State state = {false, 0, 0};
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Controller API
|
||||
// All no-ops as we are fuzzing.
|
||||
//--------------------------------------------------------------------+
|
||||
extern "C" {
|
||||
bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
|
||||
UNUSED(rhport);
|
||||
UNUSED(rh_init);
|
||||
return true;
|
||||
}
|
||||
|
||||
void dcd_int_handler(uint8_t rhport) {
|
||||
assert(_fuzz_data_provider.has_value());
|
||||
|
||||
if (!state.interrupts_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Choose if we want to generate a signal based on the fuzzed data.
|
||||
if (_fuzz_data_provider->ConsumeBool()) {
|
||||
dcd_event_bus_signal(
|
||||
rhport,
|
||||
// Choose a random event based on the fuzz data.
|
||||
(dcd_eventid_t)_fuzz_data_provider->ConsumeIntegralInRange<uint8_t>(
|
||||
DCD_EVENT_INVALID + 1, DCD_EVENT_COUNT - 1),
|
||||
// Identify trigger as either an interrupt or a syncrhonous call
|
||||
// depending on fuzz data.
|
||||
_fuzz_data_provider->ConsumeBool());
|
||||
}
|
||||
|
||||
if (_fuzz_data_provider->ConsumeBool()) {
|
||||
constexpr size_t kSetupFrameLength = 8;
|
||||
std::vector<uint8_t> setup =
|
||||
_fuzz_data_provider->ConsumeBytes<uint8_t>(kSetupFrameLength);
|
||||
// Fuzz consumer may return less than requested. If this is the case
|
||||
// we want to make sure that at least that length is allocated and available
|
||||
// to the signal handler.
|
||||
if (setup.size() != kSetupFrameLength) {
|
||||
setup.resize(kSetupFrameLength);
|
||||
}
|
||||
dcd_event_setup_received(rhport, setup.data(),
|
||||
// Identify trigger as either an interrupt or a
|
||||
// syncrhonous call depending on fuzz data.
|
||||
_fuzz_data_provider->ConsumeBool());
|
||||
}
|
||||
}
|
||||
|
||||
void dcd_int_enable(uint8_t rhport) {
|
||||
state.interrupts_enabled = true;
|
||||
UNUSED(rhport);
|
||||
return;
|
||||
}
|
||||
|
||||
void dcd_int_disable(uint8_t rhport) {
|
||||
state.interrupts_enabled = false;
|
||||
UNUSED(rhport);
|
||||
return;
|
||||
}
|
||||
|
||||
void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
|
||||
UNUSED(rhport);
|
||||
state.address = dev_addr;
|
||||
// Respond with status.
|
||||
dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
void dcd_remote_wakeup(uint8_t rhport) {
|
||||
UNUSED(rhport);
|
||||
return;
|
||||
}
|
||||
|
||||
void dcd_connect(uint8_t rhport) {
|
||||
UNUSED(rhport);
|
||||
return;
|
||||
}
|
||||
|
||||
void dcd_disconnect(uint8_t rhport) {
|
||||
UNUSED(rhport);
|
||||
return;
|
||||
}
|
||||
|
||||
void dcd_sof_enable(uint8_t rhport, bool en) {
|
||||
state.sof_enabled = en;
|
||||
UNUSED(rhport);
|
||||
return;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Endpoint API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Configure endpoint's registers according to descriptor
|
||||
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) {
|
||||
UNUSED(rhport);
|
||||
UNUSED(desc_ep);
|
||||
return _fuzz_data_provider->ConsumeBool();
|
||||
}
|
||||
|
||||
// Close all non-control endpoints, cancel all pending transfers if any.
|
||||
// Invoked when switching from a non-zero Configuration by SET_CONFIGURE
|
||||
// therefore required for multiple configuration support.
|
||||
void dcd_edpt_close_all(uint8_t rhport) {
|
||||
UNUSED(rhport);
|
||||
return;
|
||||
}
|
||||
|
||||
// Close an endpoint.
|
||||
// Since it is weak, caller must TU_ASSERT this function's existence before
|
||||
// calling it.
|
||||
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
|
||||
UNUSED(rhport);
|
||||
UNUSED(ep_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to
|
||||
// notify the stack
|
||||
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer,
|
||||
uint16_t total_bytes) {
|
||||
UNUSED(rhport);
|
||||
UNUSED(buffer);
|
||||
UNUSED(total_bytes);
|
||||
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
if (dir == TUSB_DIR_IN) {
|
||||
std::vector<uint8_t> temp =
|
||||
_fuzz_data_provider->ConsumeBytes<uint8_t>(total_bytes);
|
||||
std::copy(temp.begin(), temp.end(), buffer);
|
||||
}
|
||||
// Ignore output data as it's not useful for fuzzing without a more
|
||||
// complex fuzzed backend. But we need to make sure it's not
|
||||
// optimised out.
|
||||
volatile uint8_t *dont_optimise0 = buffer;
|
||||
volatile uint16_t dont_optimise1 = total_bytes;
|
||||
UNUSED(dont_optimise0);
|
||||
UNUSED(dont_optimise1);
|
||||
|
||||
|
||||
return _fuzz_data_provider->ConsumeBool();
|
||||
}
|
||||
|
||||
/* TODO: implement a fuzzed version of this.
|
||||
bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff,
|
||||
uint16_t total_bytes) {}
|
||||
*/
|
||||
|
||||
// Stall endpoint, any queuing transfer should be removed from endpoint
|
||||
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
|
||||
|
||||
UNUSED(rhport);
|
||||
UNUSED(ep_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
// clear stall, data toggle is also reset to DATA0
|
||||
// This API never calls with control endpoints, since it is auto cleared when
|
||||
// receiving setup packet
|
||||
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
|
||||
|
||||
UNUSED(rhport);
|
||||
UNUSED(ep_addr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
|
||||
|
||||
# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
|
||||
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
project(${PROJECT})
|
||||
|
||||
# Checks this example is valid for the family and initializes the project
|
||||
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
add_executable(${PROJECT})
|
||||
|
||||
# Example source
|
||||
target_sources(${PROJECT} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
|
||||
)
|
||||
|
||||
# Example include
|
||||
target_include_directories(${PROJECT} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
)
|
||||
|
||||
# Configure compilation flags and libraries for the example without RTOS.
|
||||
# See the corresponding function in hw/bsp/FAMILY/family.cmake for details.
|
||||
family_configure_device_example(${PROJECT} noos)
|
||||
@@ -0,0 +1,11 @@
|
||||
include ../../make.mk
|
||||
|
||||
INC += \
|
||||
src \
|
||||
$(TOP)/hw \
|
||||
|
||||
# Example source
|
||||
SRC_C += $(addprefix $(CURRENT_PATH)/, $(wildcard src/*.c))
|
||||
SRC_CXX += $(addprefix $(CURRENT_PATH)/, $(wildcard src/*.cc))
|
||||
|
||||
include ../../rules.mk
|
||||
Binary file not shown.
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Nathaniel Brough
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "class/cdc/cdc_device.h"
|
||||
#include "fuzz/fuzz.h"
|
||||
#include "tusb.h"
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
|
||||
#define FUZZ_ITERATIONS 500
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF PROTYPES
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void cdc_task(FuzzedDataProvider *provider);
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
FuzzedDataProvider provider(Data, Size);
|
||||
std::vector<uint8_t> callback_data = provider.ConsumeBytes<uint8_t>(
|
||||
provider.ConsumeIntegralInRange<size_t>(0, Size));
|
||||
fuzz_init(callback_data.data(), callback_data.size());
|
||||
// init device stack on configured roothub port
|
||||
tud_init(BOARD_TUD_RHPORT);
|
||||
|
||||
for (int i = 0; i < FUZZ_ITERATIONS; i++) {
|
||||
if (provider.remaining_bytes() == 0) {
|
||||
return 0;
|
||||
}
|
||||
tud_int_handler(provider.ConsumeIntegral<uint8_t>());
|
||||
tud_task(); // tinyusb device task
|
||||
cdc_task(&provider);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USB CDC
|
||||
//--------------------------------------------------------------------+
|
||||
enum CdcApiFuncs {
|
||||
kCdcNConnected,
|
||||
kCdcNGetLineState,
|
||||
kCdcNGetLineCoding,
|
||||
kCdcNSetWantedChar,
|
||||
kCdcNAvailable,
|
||||
kCdcNRead,
|
||||
kCdcNReadChar,
|
||||
kCdcNReadFlush,
|
||||
kCdcNPeek,
|
||||
kCdcNWrite,
|
||||
kCdcNWriteChar,
|
||||
kCdcNWriteStr,
|
||||
kCdcNWriteFlush,
|
||||
kCdcNWriteAvailable,
|
||||
kCdcNWriteClear,
|
||||
// We don't need to fuzz tud_cdc_<not n>* as they are just wrappers
|
||||
// calling with n==0.
|
||||
kMaxValue,
|
||||
};
|
||||
|
||||
void cdc_task(FuzzedDataProvider *provider) {
|
||||
|
||||
assert(provider != NULL);
|
||||
const int kMaxBufferSize = 4096;
|
||||
switch (provider->ConsumeEnum<CdcApiFuncs>()) {
|
||||
case kCdcNConnected:
|
||||
// TODO: Fuzz interface number
|
||||
(void)tud_cdc_n_connected(0);
|
||||
break;
|
||||
case kCdcNGetLineState:
|
||||
// TODO: Fuzz interface number
|
||||
(void)tud_cdc_n_get_line_state(0);
|
||||
break;
|
||||
case kCdcNGetLineCoding: {
|
||||
cdc_line_coding_t coding;
|
||||
// TODO: Fuzz interface number
|
||||
(void)tud_cdc_n_get_line_coding(0, &coding);
|
||||
} break;
|
||||
case kCdcNSetWantedChar:
|
||||
// TODO: Fuzz interface number
|
||||
(void)tud_cdc_n_set_wanted_char(0, provider->ConsumeIntegral<char>());
|
||||
break;
|
||||
case kCdcNAvailable:
|
||||
// TODO: Fuzz interface number
|
||||
(void)tud_cdc_n_available(0);
|
||||
break;
|
||||
case kCdcNRead: {
|
||||
std::vector<uint8_t> buffer;
|
||||
buffer.resize(provider->ConsumeIntegralInRange<size_t>(0, kMaxBufferSize));
|
||||
// TODO: Fuzz interface number
|
||||
(void)tud_cdc_n_read(0, buffer.data(), buffer.size());
|
||||
break;
|
||||
}
|
||||
case kCdcNReadChar:
|
||||
// TODO: Fuzz interface number
|
||||
tud_cdc_n_read_char(0);
|
||||
break;
|
||||
case kCdcNReadFlush:
|
||||
// TODO: Fuzz interface number
|
||||
tud_cdc_n_read_flush(0);
|
||||
break;
|
||||
case kCdcNPeek: {
|
||||
uint8_t peak = 0;
|
||||
tud_cdc_n_peek(0, &peak);
|
||||
break;
|
||||
}
|
||||
case kCdcNWrite: {
|
||||
std::vector<uint8_t> buffer = provider->ConsumeBytes<uint8_t>(
|
||||
provider->ConsumeIntegralInRange<size_t>(0, kMaxBufferSize));
|
||||
|
||||
// TODO: Fuzz interface number
|
||||
(void)tud_cdc_n_write(0, buffer.data(), buffer.size());
|
||||
} break;
|
||||
|
||||
case kCdcNWriteChar:
|
||||
// TODO: Fuzz interface number
|
||||
(void)tud_cdc_n_write_char(0, provider->ConsumeIntegral<char>());
|
||||
break;
|
||||
case kCdcNWriteStr: {
|
||||
std::string str = provider->ConsumeRandomLengthString(kMaxBufferSize);
|
||||
// TODO: Fuzz interface number
|
||||
(void)tud_cdc_n_write_str(0, str.c_str());
|
||||
break;
|
||||
}
|
||||
case kCdcNWriteFlush:
|
||||
// TODO: Fuzz interface number
|
||||
(void)tud_cdc_n_write_flush(0);
|
||||
break;
|
||||
case kCdcNWriteAvailable:
|
||||
// TODO: Fuzz interface number
|
||||
(void)tud_cdc_n_write_available(0);
|
||||
break;
|
||||
case kCdcNWriteClear:
|
||||
// TODO: Fuzz interface number
|
||||
(void)tud_cdc_n_write_clear(0);
|
||||
break;
|
||||
case kMaxValue:
|
||||
// Noop.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Nathaniel Brough
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_CONFIG_H_
|
||||
#define _TUSB_CONFIG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Board Specific Configuration
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// RHPort number used for device can be defined by board.mk, default to port 0
|
||||
#ifndef BOARD_TUD_RHPORT
|
||||
#define BOARD_TUD_RHPORT 0
|
||||
#endif
|
||||
|
||||
// RHPort max operational speed can defined by board.mk
|
||||
#ifndef BOARD_TUD_MAX_SPEED
|
||||
#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Common Configuration
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// defined by compiler flags for flexibility
|
||||
#ifndef CFG_TUSB_MCU
|
||||
#error CFG_TUSB_MCU must be defined
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_OS
|
||||
#define CFG_TUSB_OS OPT_OS_NONE
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_DEBUG
|
||||
#define CFG_TUSB_DEBUG 0
|
||||
#endif
|
||||
|
||||
// Enable Device stack
|
||||
#define CFG_TUD_ENABLED 1
|
||||
|
||||
// Default is max speed that hardware controller could support with on-chip PHY
|
||||
#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED
|
||||
|
||||
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||
* into those specific section.
|
||||
* e.g
|
||||
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
|
||||
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
|
||||
*/
|
||||
#ifndef CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_MEM_ALIGN
|
||||
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DEVICE CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
#define CFG_TUD_CDC 1
|
||||
#define CFG_TUD_MSC 0
|
||||
#define CFG_TUD_HID 0
|
||||
#define CFG_TUD_MIDI 0
|
||||
#define CFG_TUD_VENDOR 0
|
||||
|
||||
// CDC FIFO size of TX and RX
|
||||
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
|
||||
// CDC Endpoint transfer buffer size, more is faster
|
||||
#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
|
||||
// MSC Buffer size of Device Mass storage
|
||||
#define CFG_TUD_MSC_EP_BUFSIZE 512
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CONFIG_H_ */
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Nathaniel Brough
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tusb.h"
|
||||
|
||||
/* A combination of interfaces must have a unique product id, since PC will save
|
||||
* device driver after the first plug.
|
||||
* Auto ProductID layout's Bitmap:
|
||||
* [MSB] HID | CDC [LSB]
|
||||
*/
|
||||
#define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n))
|
||||
#define USB_PID \
|
||||
(0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(HID, 2) | _PID_MAP(MIDI, 3) | \
|
||||
_PID_MAP(VENDOR, 4))
|
||||
|
||||
#define USB_VID 0xCafe
|
||||
#define USB_BCD 0x0200
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Device Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when received GET DEVICE DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
uint8_t const *tud_descriptor_device_cb(void) {
|
||||
static tusb_desc_device_t const desc_device = {
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = USB_BCD,
|
||||
|
||||
// Use Interface Association Descriptor (IAD) for CDC
|
||||
// As required by USB Specs IAD's subclass must be common class (2) and
|
||||
// protocol must be IAD (1)
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
|
||||
.idVendor = USB_VID,
|
||||
.idProduct = USB_PID,
|
||||
.bcdDevice = 0x0100,
|
||||
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
|
||||
.bNumConfigurations = 0x01};
|
||||
|
||||
return (uint8_t const *)&desc_device;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Configuration Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
enum { ITF_NUM_CDC = 0, ITF_NUM_CDC_DATA, ITF_NUM_TOTAL };
|
||||
|
||||
#define EPNUM_CDC_NOTIF 0x81
|
||||
#define EPNUM_CDC_OUT 0x02
|
||||
#define EPNUM_CDC_IN 0x82
|
||||
|
||||
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
|
||||
|
||||
// full speed configuration
|
||||
uint8_t const desc_fs_configuration[] = {
|
||||
// Config number, interface count, string index, total length, attribute,
|
||||
// power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
|
||||
|
||||
// Interface number, string index, EP notification address and size, EP data
|
||||
// address (out, in) and size.
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT,
|
||||
EPNUM_CDC_IN, 64),
|
||||
};
|
||||
|
||||
#if TUD_OPT_HIGH_SPEED
|
||||
// Per USB specs: high speed capable device must report device_qualifier and
|
||||
// other_speed_configuration
|
||||
|
||||
// high speed configuration
|
||||
uint8_t const desc_hs_configuration[] = {
|
||||
// Config number, interface count, string index, total length, attribute,
|
||||
// power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
|
||||
|
||||
// Interface number, string index, EP notification address and size, EP data
|
||||
// address (out, in) and size.
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT,
|
||||
EPNUM_CDC_IN, 512),
|
||||
};
|
||||
|
||||
// other speed configuration
|
||||
uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN];
|
||||
|
||||
// device qualifier is mostly similar to device descriptor since we don't change
|
||||
// configuration based on speed
|
||||
tusb_desc_device_qualifier_t const desc_device_qualifier = {
|
||||
.bLength = sizeof(tusb_desc_device_qualifier_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
|
||||
.bcdUSB = USB_BCD,
|
||||
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.bNumConfigurations = 0x01,
|
||||
.bReserved = 0x00};
|
||||
|
||||
// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long
|
||||
// enough for transfer to complete. device_qualifier descriptor describes
|
||||
// information about a high-speed capable device that would change if the device
|
||||
// were operating at the other speed. If not highspeed capable stall this
|
||||
// request.
|
||||
uint8_t const *tud_descriptor_device_qualifier_cb(void) {
|
||||
return (uint8_t const *)&desc_device_qualifier;
|
||||
}
|
||||
|
||||
// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long
|
||||
// enough for transfer to complete Configuration descriptor in the other speed
|
||||
// e.g if high speed then this is for full speed and vice versa
|
||||
uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {
|
||||
(void)index; // for multiple configurations
|
||||
|
||||
// if link speed is high return fullspeed config, and vice versa
|
||||
// Note: the descriptor type is OTHER_SPEED_CONFIG instead of CONFIG
|
||||
memcpy(desc_other_speed_config,
|
||||
(tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration
|
||||
: desc_hs_configuration,
|
||||
CONFIG_TOTAL_LEN);
|
||||
|
||||
desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
|
||||
|
||||
return desc_other_speed_config;
|
||||
}
|
||||
|
||||
#endif // highspeed
|
||||
|
||||
// Invoked when received GET CONFIGURATION DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
// Descriptor contents must exist long enough for transfer to complete
|
||||
uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
|
||||
(void)index; // for multiple configurations
|
||||
|
||||
#if TUD_OPT_HIGH_SPEED
|
||||
// Although we are highspeed, host may be fullspeed.
|
||||
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration
|
||||
: desc_fs_configuration;
|
||||
#else
|
||||
return desc_fs_configuration;
|
||||
#endif
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// String Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// array of pointer to string descriptors
|
||||
char const *string_desc_arr[] = {
|
||||
(const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
|
||||
"TinyUSB", // 1: Manufacturer
|
||||
"TinyUSB Device", // 2: Product
|
||||
"123456789012", // 3: Serials, should use chip ID
|
||||
"TinyUSB CDC", // 4: CDC Interface
|
||||
};
|
||||
|
||||
static uint16_t _desc_str[32];
|
||||
|
||||
// Invoked when received GET STRING DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long
|
||||
// enough for transfer to complete
|
||||
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
||||
(void)langid;
|
||||
|
||||
uint8_t chr_count;
|
||||
|
||||
if (index == 0) {
|
||||
memcpy(&_desc_str[1], string_desc_arr[0], 2);
|
||||
chr_count = 1;
|
||||
} else {
|
||||
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
|
||||
|
||||
if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])))
|
||||
return NULL;
|
||||
|
||||
const char *str = string_desc_arr[index];
|
||||
|
||||
// Cap at max char
|
||||
chr_count = (uint8_t)strlen(str);
|
||||
if (chr_count > 31)
|
||||
chr_count = 31;
|
||||
|
||||
// Convert ASCII string into UTF-16
|
||||
for (uint8_t i = 0; i < chr_count; i++) {
|
||||
_desc_str[1 + i] = str[i];
|
||||
}
|
||||
}
|
||||
|
||||
// first byte is length (including header), second byte is string type
|
||||
_desc_str[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
|
||||
|
||||
return _desc_str;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
|
||||
|
||||
# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
|
||||
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
project(${PROJECT})
|
||||
|
||||
# Checks this example is valid for the family and initializes the project
|
||||
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
add_executable(${PROJECT})
|
||||
|
||||
# Example source
|
||||
target_sources(${PROJECT} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
|
||||
)
|
||||
|
||||
# Example include
|
||||
target_include_directories(${PROJECT} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
)
|
||||
|
||||
# Configure compilation flags and libraries for the example without RTOS.
|
||||
# See the corresponding function in hw/bsp/FAMILY/family.cmake for details.
|
||||
family_configure_device_example(${PROJECT} noos)
|
||||
@@ -0,0 +1,11 @@
|
||||
include ../../make.mk
|
||||
|
||||
INC += \
|
||||
src \
|
||||
$(TOP)/hw \
|
||||
|
||||
# Example source
|
||||
SRC_C += $(addprefix $(CURRENT_PATH)/, $(wildcard src/*.c))
|
||||
SRC_CXX += $(addprefix $(CURRENT_PATH)/, $(wildcard src/*.cc))
|
||||
|
||||
include ../../rules.mk
|
||||
Binary file not shown.
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Nathaniel Brough
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "class/cdc/cdc_device.h"
|
||||
#include "fuzz/fuzz.h"
|
||||
#include "tusb.h"
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF PROTYPES
|
||||
//--------------------------------------------------------------------+
|
||||
#define FUZZ_ITERATIONS 500
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
FuzzedDataProvider provider(Data, Size);
|
||||
std::vector<uint8_t> callback_data = provider.ConsumeBytes<uint8_t>(
|
||||
provider.ConsumeIntegralInRange<size_t>(0, Size));
|
||||
fuzz_init(callback_data.data(), callback_data.size());
|
||||
// init device stack on configured roothub port
|
||||
tud_init(BOARD_TUD_RHPORT);
|
||||
|
||||
for (int i = 0; i < FUZZ_ITERATIONS; i++) {
|
||||
if (provider.remaining_bytes() == 0) {
|
||||
return 0;
|
||||
}
|
||||
tud_int_handler(provider.ConsumeIntegral<uint8_t>());
|
||||
tud_task(); // tinyusb device task
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Nathaniel Brough
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_CONFIG_H_
|
||||
#define _TUSB_CONFIG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Board Specific Configuration
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// RHPort number used for device can be defined by board.mk, default to port 0
|
||||
#ifndef BOARD_TUD_RHPORT
|
||||
#define BOARD_TUD_RHPORT 0
|
||||
#endif
|
||||
|
||||
// RHPort max operational speed can defined by board.mk
|
||||
#ifndef BOARD_TUD_MAX_SPEED
|
||||
#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Common Configuration
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// defined by compiler flags for flexibility
|
||||
#ifndef CFG_TUSB_MCU
|
||||
#error CFG_TUSB_MCU must be defined
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_OS
|
||||
#define CFG_TUSB_OS OPT_OS_NONE
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_DEBUG
|
||||
#define CFG_TUSB_DEBUG 0
|
||||
#endif
|
||||
|
||||
// Enable Device stack
|
||||
#define CFG_TUD_ENABLED 1
|
||||
|
||||
// Default is max speed that hardware controller could support with on-chip PHY
|
||||
#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED
|
||||
|
||||
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||
* into those specific section.
|
||||
* e.g
|
||||
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
|
||||
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
|
||||
*/
|
||||
#ifndef CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_MEM_ALIGN
|
||||
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DEVICE CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
#define CFG_TUD_CDC 0
|
||||
#define CFG_TUD_MSC 1
|
||||
#define CFG_TUD_HID 0
|
||||
#define CFG_TUD_MIDI 0
|
||||
#define CFG_TUD_VENDOR 0
|
||||
|
||||
// CDC FIFO size of TX and RX
|
||||
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
|
||||
// CDC Endpoint transfer buffer size, more is faster
|
||||
#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
|
||||
// MSC Buffer size of Device Mass storage
|
||||
#define CFG_TUD_MSC_EP_BUFSIZE 512
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CONFIG_H_ */
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Nathaniel Brough
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tusb.h"
|
||||
|
||||
/* A combination of interfaces must have a unique product id, since PC will save
|
||||
* device driver after the first plug.
|
||||
* Auto ProductID layout's Bitmap:
|
||||
* [MSB] HID | MSC | CDC [LSB]
|
||||
*/
|
||||
#define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n))
|
||||
#define USB_PID \
|
||||
(0x4000 | _PID_MAP(MSC, 0) | _PID_MAP(HID, 1) | _PID_MAP(MIDI, 2) | \
|
||||
_PID_MAP(VENDOR, 3))
|
||||
#define USB_VID 0xCafe
|
||||
#define USB_BCD 0x0200
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Device Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when received GET DEVICE DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
uint8_t const *tud_descriptor_device_cb(void) {
|
||||
tu_static tusb_desc_device_t const desc_device = {
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = USB_BCD,
|
||||
|
||||
// Use Interface Association Descriptor (IAD) for CDC
|
||||
// As required by USB Specs IAD's subclass must be common class (2) and
|
||||
// protocol must be IAD (1)
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
|
||||
.idVendor = USB_VID,
|
||||
.idProduct = USB_PID,
|
||||
.bcdDevice = 0x0100,
|
||||
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
|
||||
.bNumConfigurations = 0x01};
|
||||
|
||||
return (uint8_t const *)&desc_device;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Configuration Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
enum { ITF_NUM_MSC = 0, ITF_NUM_TOTAL };
|
||||
|
||||
#define EPNUM_MSC_OUT 0x05
|
||||
#define EPNUM_MSC_IN 0x85
|
||||
|
||||
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN)
|
||||
|
||||
// full speed configuration
|
||||
uint8_t const desc_fs_configuration[] = {
|
||||
// Config number, interface count, string index, total length, attribute,
|
||||
// power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
|
||||
|
||||
// Interface number, string index, EP Out & EP In address, EP size
|
||||
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 4, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64),
|
||||
};
|
||||
|
||||
#if TUD_OPT_HIGH_SPEED
|
||||
// Per USB specs: high speed capable device must report device_qualifier and
|
||||
// other_speed_configuration
|
||||
|
||||
// high speed configuration
|
||||
uint8_t const desc_hs_configuration[] = {
|
||||
// Config number, interface count, string index, total length, attribute,
|
||||
// power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
|
||||
|
||||
// Interface number, string index, EP Out & EP In address, EP size
|
||||
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 4, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512),
|
||||
};
|
||||
|
||||
// other speed configuration
|
||||
uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN];
|
||||
|
||||
// device qualifier is mostly similar to device descriptor since we don't change
|
||||
// configuration based on speed
|
||||
tusb_desc_device_qualifier_t const desc_device_qualifier = {
|
||||
.bLength = sizeof(tusb_desc_device_qualifier_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
|
||||
.bcdUSB = USB_BCD,
|
||||
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.bNumConfigurations = 0x01,
|
||||
.bReserved = 0x00};
|
||||
|
||||
// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long
|
||||
// enough for transfer to complete. device_qualifier descriptor describes
|
||||
// information about a high-speed capable device that would change if the device
|
||||
// were operating at the other speed. If not highspeed capable stall this
|
||||
// request.
|
||||
uint8_t const *tud_descriptor_device_qualifier_cb(void) {
|
||||
return (uint8_t const *)&desc_device_qualifier;
|
||||
}
|
||||
|
||||
// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long
|
||||
// enough for transfer to complete Configuration descriptor in the other speed
|
||||
// e.g if high speed then this is for full speed and vice versa
|
||||
uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {
|
||||
(void)index; // for multiple configurations
|
||||
|
||||
// if link speed is high return fullspeed config, and vice versa
|
||||
// Note: the descriptor type is OTHER_SPEED_CONFIG instead of CONFIG
|
||||
memcpy(desc_other_speed_config,
|
||||
(tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration
|
||||
: desc_hs_configuration,
|
||||
CONFIG_TOTAL_LEN);
|
||||
|
||||
desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
|
||||
|
||||
return desc_other_speed_config;
|
||||
}
|
||||
|
||||
#endif // highspeed
|
||||
|
||||
// Invoked when received GET CONFIGURATION DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
// Descriptor contents must exist long enough for transfer to complete
|
||||
uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
|
||||
(void)index; // for multiple configurations
|
||||
|
||||
#if TUD_OPT_HIGH_SPEED
|
||||
// Although we are highspeed, host may be fullspeed.
|
||||
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration
|
||||
: desc_fs_configuration;
|
||||
#else
|
||||
return desc_fs_configuration;
|
||||
#endif
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// String Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// array of pointer to string descriptors
|
||||
char const *string_desc_arr[] = {
|
||||
(const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
|
||||
"TinyUSB", // 1: Manufacturer
|
||||
"TinyUSB Device", // 2: Product
|
||||
"123456789012", // 3: Serials, should use chip ID
|
||||
"TinyUSB MSC", // 4: MSC Interface
|
||||
|
||||
};
|
||||
|
||||
tu_static uint16_t _desc_str[32];
|
||||
|
||||
// Invoked when received GET STRING DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long
|
||||
// enough for transfer to complete
|
||||
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
||||
(void)langid;
|
||||
|
||||
uint8_t chr_count;
|
||||
|
||||
if (index == 0) {
|
||||
memcpy(&_desc_str[1], string_desc_arr[0], 2);
|
||||
chr_count = 1;
|
||||
} else {
|
||||
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
|
||||
|
||||
if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])))
|
||||
return NULL;
|
||||
|
||||
const char *str = string_desc_arr[index];
|
||||
|
||||
// Cap at max char
|
||||
chr_count = (uint8_t)strlen(str);
|
||||
if (chr_count > 31)
|
||||
chr_count = 31;
|
||||
|
||||
// Convert ASCII string into UTF-16
|
||||
for (uint8_t i = 0; i < chr_count; i++) {
|
||||
_desc_str[1 + i] = str[i];
|
||||
}
|
||||
}
|
||||
|
||||
// first byte is length (including header), second byte is string type
|
||||
_desc_str[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
|
||||
|
||||
return _desc_str;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
|
||||
|
||||
# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
|
||||
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
project(${PROJECT})
|
||||
|
||||
# Checks this example is valid for the family and initializes the project
|
||||
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
add_executable(${PROJECT})
|
||||
|
||||
# Example source
|
||||
target_sources(${PROJECT} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
|
||||
)
|
||||
|
||||
# Example include
|
||||
target_include_directories(${PROJECT} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
)
|
||||
|
||||
# Configure compilation flags and libraries for the example without RTOS.
|
||||
# See the corresponding function in hw/bsp/FAMILY/family.cmake for details.
|
||||
family_configure_device_example(${PROJECT} noos)
|
||||
@@ -0,0 +1,68 @@
|
||||
include ../../make.mk
|
||||
|
||||
# suppress warning caused by lwip
|
||||
CFLAGS += \
|
||||
-Wno-error=null-dereference \
|
||||
-Wno-error=unused-parameter \
|
||||
-Wno-error=unused-variable
|
||||
|
||||
INC += \
|
||||
src \
|
||||
$(TOP)/hw \
|
||||
$(TOP)/lib/lwip/src/include \
|
||||
$(TOP)/lib/lwip/src/include/ipv4 \
|
||||
$(TOP)/lib/lwip/src/include/lwip/apps \
|
||||
$(TOP)/lib/networking
|
||||
|
||||
# Example source
|
||||
SRC_C += $(addprefix $(CURRENT_PATH)/, $(wildcard src/*.c))
|
||||
SRC_CXX += $(addprefix $(CURRENT_PATH)/, $(wildcard src/*.cc))
|
||||
|
||||
# lwip sources
|
||||
SRC_C += \
|
||||
lib/lwip/src/core/altcp.c \
|
||||
lib/lwip/src/core/altcp_alloc.c \
|
||||
lib/lwip/src/core/altcp_tcp.c \
|
||||
lib/lwip/src/core/def.c \
|
||||
lib/lwip/src/core/dns.c \
|
||||
lib/lwip/src/core/inet_chksum.c \
|
||||
lib/lwip/src/core/init.c \
|
||||
lib/lwip/src/core/ip.c \
|
||||
lib/lwip/src/core/mem.c \
|
||||
lib/lwip/src/core/memp.c \
|
||||
lib/lwip/src/core/netif.c \
|
||||
lib/lwip/src/core/pbuf.c \
|
||||
lib/lwip/src/core/raw.c \
|
||||
lib/lwip/src/core/stats.c \
|
||||
lib/lwip/src/core/sys.c \
|
||||
lib/lwip/src/core/tcp.c \
|
||||
lib/lwip/src/core/tcp_in.c \
|
||||
lib/lwip/src/core/tcp_out.c \
|
||||
lib/lwip/src/core/timeouts.c \
|
||||
lib/lwip/src/core/udp.c \
|
||||
lib/lwip/src/core/ipv4/autoip.c \
|
||||
lib/lwip/src/core/ipv4/dhcp.c \
|
||||
lib/lwip/src/core/ipv4/etharp.c \
|
||||
lib/lwip/src/core/ipv4/icmp.c \
|
||||
lib/lwip/src/core/ipv4/igmp.c \
|
||||
lib/lwip/src/core/ipv4/ip4.c \
|
||||
lib/lwip/src/core/ipv4/ip4_addr.c \
|
||||
lib/lwip/src/core/ipv4/ip4_frag.c \
|
||||
lib/lwip/src/core/ipv6/dhcp6.c \
|
||||
lib/lwip/src/core/ipv6/ethip6.c \
|
||||
lib/lwip/src/core/ipv6/icmp6.c \
|
||||
lib/lwip/src/core/ipv6/inet6.c \
|
||||
lib/lwip/src/core/ipv6/ip6.c \
|
||||
lib/lwip/src/core/ipv6/ip6_addr.c \
|
||||
lib/lwip/src/core/ipv6/ip6_frag.c \
|
||||
lib/lwip/src/core/ipv6/mld6.c \
|
||||
lib/lwip/src/core/ipv6/nd6.c \
|
||||
lib/lwip/src/netif/ethernet.c \
|
||||
lib/lwip/src/netif/slipif.c \
|
||||
lib/lwip/src/apps/http/httpd.c \
|
||||
lib/lwip/src/apps/http/fs.c \
|
||||
lib/networking/dhserver.c \
|
||||
lib/networking/dnserver.c \
|
||||
lib/networking/rndis_reports.c
|
||||
|
||||
include ../../rules.mk
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
#ifndef __CC_H__
|
||||
#define __CC_H__
|
||||
|
||||
//#include "cpu.h"
|
||||
|
||||
typedef int sys_prot_t;
|
||||
|
||||
|
||||
|
||||
/* define compiler specific symbols */
|
||||
#if defined (__ICCARM__)
|
||||
|
||||
#define PACK_STRUCT_BEGIN
|
||||
#define PACK_STRUCT_STRUCT
|
||||
#define PACK_STRUCT_END
|
||||
#define PACK_STRUCT_FIELD(x) x
|
||||
#define PACK_STRUCT_USE_INCLUDES
|
||||
|
||||
#elif defined (__CC_ARM)
|
||||
|
||||
#define PACK_STRUCT_BEGIN __packed
|
||||
#define PACK_STRUCT_STRUCT
|
||||
#define PACK_STRUCT_END
|
||||
#define PACK_STRUCT_FIELD(x) x
|
||||
|
||||
#elif defined (__GNUC__)
|
||||
|
||||
#define PACK_STRUCT_BEGIN
|
||||
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
|
||||
#define PACK_STRUCT_END
|
||||
#define PACK_STRUCT_FIELD(x) x
|
||||
|
||||
#elif defined (__TASKING__)
|
||||
|
||||
#define PACK_STRUCT_BEGIN
|
||||
#define PACK_STRUCT_STRUCT
|
||||
#define PACK_STRUCT_END
|
||||
#define PACK_STRUCT_FIELD(x) x
|
||||
|
||||
#endif
|
||||
|
||||
#define LWIP_PLATFORM_ASSERT(x) do { if(!(x)) while(1); } while(0)
|
||||
|
||||
#endif /* __CC_H__ */
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Nathaniel Brough
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "class/cdc/cdc_device.h"
|
||||
#include "class/net/net_device.h"
|
||||
#include "fuzz/fuzz.h"
|
||||
#include "tusb.h"
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
|
||||
#define FUZZ_ITERATIONS 500
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF PROTYPES
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void net_task(FuzzedDataProvider *provider);
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
FuzzedDataProvider provider(Data, Size);
|
||||
std::vector<uint8_t> callback_data = provider.ConsumeBytes<uint8_t>(
|
||||
provider.ConsumeIntegralInRange<size_t>(0, Size));
|
||||
fuzz_init(callback_data.data(), callback_data.size());
|
||||
// init device stack on configured roothub port
|
||||
tud_init(BOARD_TUD_RHPORT);
|
||||
|
||||
for (int i = 0; i < FUZZ_ITERATIONS; i++) {
|
||||
if (provider.remaining_bytes() == 0) {
|
||||
return 0;
|
||||
}
|
||||
tud_int_handler(provider.ConsumeIntegral<uint8_t>());
|
||||
tud_task(); // tinyusb device task
|
||||
net_task(&provider);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USB CDC
|
||||
//--------------------------------------------------------------------+
|
||||
enum NetApiFuncs {
|
||||
kNetworkRecvRenew,
|
||||
kNetworkCanXmit,
|
||||
kNetworkXmit,
|
||||
kMaxValue,
|
||||
};
|
||||
|
||||
void net_task(FuzzedDataProvider *provider) {
|
||||
|
||||
assert(provider != NULL);
|
||||
switch (provider->ConsumeEnum<NetApiFuncs>()) {
|
||||
|
||||
case kNetworkRecvRenew:
|
||||
tud_network_recv_renew();
|
||||
break;
|
||||
case kNetworkCanXmit:
|
||||
(void)tud_network_can_xmit(provider->ConsumeIntegral<uint16_t>());
|
||||
case kNetworkXmit:
|
||||
// TODO: Actually pass real values here later.
|
||||
tud_network_xmit(NULL, 0);
|
||||
|
||||
case kMaxValue:
|
||||
// Noop.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Simon Goldschmidt
|
||||
*
|
||||
*/
|
||||
#ifndef __LWIPOPTS_H__
|
||||
#define __LWIPOPTS_H__
|
||||
|
||||
/* Prevent having to link sys_arch.c (we don't test the API layers in unit tests) */
|
||||
#define NO_SYS 1
|
||||
#define MEM_ALIGNMENT 4
|
||||
#define LWIP_RAW 0
|
||||
#define LWIP_NETCONN 0
|
||||
#define LWIP_SOCKET 0
|
||||
#define LWIP_DHCP 0
|
||||
#define LWIP_ICMP 1
|
||||
#define LWIP_UDP 1
|
||||
#define LWIP_TCP 1
|
||||
#define LWIP_IPV4 1
|
||||
#define LWIP_IPV6 0
|
||||
#define ETH_PAD_SIZE 0
|
||||
#define LWIP_IP_ACCEPT_UDP_PORT(p) ((p) == PP_NTOHS(67))
|
||||
|
||||
#define TCP_MSS (1500 /*mtu*/ - 20 /*iphdr*/ - 20 /*tcphhr*/)
|
||||
#define TCP_SND_BUF (2 * TCP_MSS)
|
||||
#define TCP_WND (TCP_MSS)
|
||||
|
||||
#define ETHARP_SUPPORT_STATIC_ENTRIES 1
|
||||
|
||||
#define LWIP_HTTPD_CGI 0
|
||||
#define LWIP_HTTPD_SSI 0
|
||||
#define LWIP_HTTPD_SSI_INCLUDE_TAG 0
|
||||
|
||||
#define LWIP_SINGLE_NETIF 1
|
||||
|
||||
#define PBUF_POOL_SIZE 2
|
||||
|
||||
#define HTTPD_USE_CUSTOM_FSDATA 0
|
||||
|
||||
#define LWIP_MULTICAST_PING 1
|
||||
#define LWIP_BROADCAST_PING 1
|
||||
#define LWIP_IPV6_MLD 0
|
||||
#define LWIP_IPV6_SEND_ROUTER_SOLICIT 0
|
||||
|
||||
#endif /* __LWIPOPTS_H__ */
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Nathaniel Brough
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_CONFIG_H_
|
||||
#define _TUSB_CONFIG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Board Specific Configuration
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// RHPort number used for device can be defined by board.mk, default to port 0
|
||||
#ifndef BOARD_TUD_RHPORT
|
||||
#define BOARD_TUD_RHPORT 0
|
||||
#endif
|
||||
|
||||
// RHPort max operational speed can defined by board.mk
|
||||
#ifndef BOARD_TUD_MAX_SPEED
|
||||
#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Common Configuration
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// defined by compiler flags for flexibility
|
||||
#ifndef CFG_TUSB_MCU
|
||||
#error CFG_TUSB_MCU must be defined
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_OS
|
||||
#define CFG_TUSB_OS OPT_OS_NONE
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_DEBUG
|
||||
#define CFG_TUSB_DEBUG 0
|
||||
#endif
|
||||
|
||||
// Enable Device stack
|
||||
#define CFG_TUD_ENABLED 1
|
||||
|
||||
// Default is max speed that hardware controller could support with on-chip PHY
|
||||
#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED
|
||||
|
||||
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||
* into those specific section.
|
||||
* e.g
|
||||
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
|
||||
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
|
||||
*/
|
||||
#ifndef CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_MEM_ALIGN
|
||||
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DEVICE CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
#define CFG_TUD_CDC 1
|
||||
#define CFG_TUD_MSC 0
|
||||
#define CFG_TUD_HID 0
|
||||
#define CFG_TUD_MIDI 0
|
||||
#define CFG_TUD_VENDOR 0
|
||||
|
||||
// Network class has 2 drivers: ECM/RNDIS and NCM.
|
||||
// Only one of the drivers can be enabled
|
||||
#define CFG_TUD_ECM_RNDIS 1
|
||||
#define CFG_TUD_NCM (1-CFG_TUD_ECM_RNDIS)
|
||||
|
||||
// CDC FIFO size of TX and RX
|
||||
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
|
||||
// CDC Endpoint transfer buffer size, more is faster
|
||||
#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
|
||||
|
||||
// MSC Buffer size of Device Mass storage
|
||||
#define CFG_TUD_MSC_EP_BUFSIZE 512
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CONFIG_H_ */
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tusb.h"
|
||||
|
||||
/* A combination of interfaces must have a unique product id, since PC will save
|
||||
* device driver after the first plug.
|
||||
* Auto ProductID layout's Bitmap:
|
||||
* [MSB] HID | CDC [LSB]
|
||||
*/
|
||||
#define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n))
|
||||
#define USB_PID \
|
||||
(0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(HID, 2) | _PID_MAP(MIDI, 3) | \
|
||||
_PID_MAP(VENDOR, 4))
|
||||
|
||||
#define USB_VID 0xCafe
|
||||
#define USB_BCD 0x0200
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Device Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when received GET DEVICE DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
uint8_t const *tud_descriptor_device_cb(void) {
|
||||
tu_static tusb_desc_device_t const desc_device = {
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = USB_BCD,
|
||||
|
||||
// Use Interface Association Descriptor (IAD) for CDC
|
||||
// As required by USB Specs IAD's subclass must be common class (2) and
|
||||
// protocol must be IAD (1)
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
|
||||
.idVendor = USB_VID,
|
||||
.idProduct = USB_PID,
|
||||
.bcdDevice = 0x0100,
|
||||
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
|
||||
.bNumConfigurations = 0x01};
|
||||
|
||||
return (uint8_t const *)&desc_device;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Configuration Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
enum { ITF_NUM_CDC = 0, ITF_NUM_CDC_DATA, ITF_NUM_TOTAL };
|
||||
|
||||
#define EPNUM_CDC_NOTIF 0x81
|
||||
#define EPNUM_CDC_OUT 0x02
|
||||
#define EPNUM_CDC_IN 0x82
|
||||
|
||||
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
|
||||
|
||||
// full speed configuration
|
||||
uint8_t const desc_fs_configuration[] = {
|
||||
// Config number, interface count, string index, total length, attribute,
|
||||
// power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
|
||||
|
||||
// Interface number, string index, EP notification address and size, EP data
|
||||
// address (out, in) and size.
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT,
|
||||
EPNUM_CDC_IN, 64),
|
||||
};
|
||||
|
||||
#if TUD_OPT_HIGH_SPEED
|
||||
// Per USB specs: high speed capable device must report device_qualifier and
|
||||
// other_speed_configuration
|
||||
|
||||
// high speed configuration
|
||||
uint8_t const desc_hs_configuration[] = {
|
||||
// Config number, interface count, string index, total length, attribute,
|
||||
// power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
|
||||
|
||||
// Interface number, string index, EP notification address and size, EP data
|
||||
// address (out, in) and size.
|
||||
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT,
|
||||
EPNUM_CDC_IN, 512),
|
||||
};
|
||||
|
||||
// other speed configuration
|
||||
uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN];
|
||||
|
||||
// device qualifier is mostly similar to device descriptor since we don't change
|
||||
// configuration based on speed
|
||||
tusb_desc_device_qualifier_t const desc_device_qualifier = {
|
||||
.bLength = sizeof(tusb_desc_device_qualifier_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
|
||||
.bcdUSB = USB_BCD,
|
||||
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
.bNumConfigurations = 0x01,
|
||||
.bReserved = 0x00};
|
||||
|
||||
// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long
|
||||
// enough for transfer to complete. device_qualifier descriptor describes
|
||||
// information about a high-speed capable device that would change if the device
|
||||
// were operating at the other speed. If not highspeed capable stall this
|
||||
// request.
|
||||
uint8_t const *tud_descriptor_device_qualifier_cb(void) {
|
||||
return (uint8_t const *)&desc_device_qualifier;
|
||||
}
|
||||
|
||||
// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long
|
||||
// enough for transfer to complete Configuration descriptor in the other speed
|
||||
// e.g if high speed then this is for full speed and vice versa
|
||||
uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {
|
||||
(void)index; // for multiple configurations
|
||||
|
||||
// if link speed is high return fullspeed config, and vice versa
|
||||
// Note: the descriptor type is OTHER_SPEED_CONFIG instead of CONFIG
|
||||
memcpy(desc_other_speed_config,
|
||||
(tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration
|
||||
: desc_hs_configuration,
|
||||
CONFIG_TOTAL_LEN);
|
||||
|
||||
desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG;
|
||||
|
||||
return desc_other_speed_config;
|
||||
}
|
||||
|
||||
#endif // highspeed
|
||||
|
||||
// Invoked when received GET CONFIGURATION DESCRIPTOR
|
||||
// Application return pointer to descriptor
|
||||
// Descriptor contents must exist long enough for transfer to complete
|
||||
uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
|
||||
(void)index; // for multiple configurations
|
||||
|
||||
#if TUD_OPT_HIGH_SPEED
|
||||
// Although we are highspeed, host may be fullspeed.
|
||||
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration
|
||||
: desc_fs_configuration;
|
||||
#else
|
||||
return desc_fs_configuration;
|
||||
#endif
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// String Descriptors
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// array of pointer to string descriptors
|
||||
char const *string_desc_arr[] = {
|
||||
(const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
|
||||
"TinyUSB", // 1: Manufacturer
|
||||
"TinyUSB Device", // 2: Product
|
||||
"123456789012", // 3: Serials, should use chip ID
|
||||
"TinyUSB CDC", // 4: CDC Interface
|
||||
};
|
||||
|
||||
tu_static uint16_t _desc_str[32];
|
||||
|
||||
// Invoked when received GET STRING DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long
|
||||
// enough for transfer to complete
|
||||
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
||||
(void)langid;
|
||||
|
||||
uint8_t chr_count;
|
||||
|
||||
if (index == 0) {
|
||||
memcpy(&_desc_str[1], string_desc_arr[0], 2);
|
||||
chr_count = 1;
|
||||
} else {
|
||||
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
|
||||
|
||||
if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])))
|
||||
return NULL;
|
||||
|
||||
const char *str = string_desc_arr[index];
|
||||
|
||||
// Cap at max char
|
||||
chr_count = (uint8_t)strlen(str);
|
||||
if (chr_count > 31)
|
||||
chr_count = 31;
|
||||
|
||||
// Convert ASCII string into UTF-16
|
||||
for (uint8_t i = 0; i < chr_count; i++) {
|
||||
_desc_str[1 + i] = str[i];
|
||||
}
|
||||
}
|
||||
|
||||
// first byte is length (including header), second byte is string type
|
||||
_desc_str[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
|
||||
|
||||
return _desc_str;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
# List of supported OIDs
|
||||
RNDIS_OID_GEN_SUPPORTED_LIST="\x00\x01\x01\x01"
|
||||
# Hardware status
|
||||
RNDIS_OID_GEN_HARDWARE_STATUS="\x00\x01\x01\x02"
|
||||
# Media types supported (encoded)
|
||||
RNDIS_OID_GEN_MEDIA_SUPPORTED="\x00\x01\x01\x03"
|
||||
# Media types in use (encoded)
|
||||
RNDIS_OID_GEN_MEDIA_IN_USE="\x00\x01\x01\x04"
|
||||
RNDIS_OID_GEN_MAXIMUM_LOOKAHEAD="\x00\x01\x01\x05"
|
||||
# Maximum frame size in bytes
|
||||
RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE="\x00\x01\x01\x06"
|
||||
# Link speed in units of 100 bps
|
||||
RNDIS_OID_GEN_LINK_SPEED="\x00\x01\x01\x07"
|
||||
# Transmit buffer space
|
||||
RNDIS_OID_GEN_TRANSMIT_BUFFER_SPACE="\x00\x01\x01\x08"
|
||||
# Receive buffer space
|
||||
RNDIS_OID_GEN_RECEIVE_BUFFER_SPACE="\x00\x01\x01\x09"
|
||||
# NDIS version number used by the driver
|
||||
RNDIS_OID_GEN_DRIVER_VERSION="\x00\x01\x01\x10"
|
||||
# Maximum total packet length in bytes
|
||||
RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE="\x00\x01\x01\x11"
|
||||
# Optional protocol flags (encoded)
|
||||
RNDIS_OID_GEN_PROTOCOL_OPTIONS="\x00\x01\x01\x12"
|
||||
# Optional NIC flags (encoded)
|
||||
RNDIS_OID_GEN_MAC_OPTIONS="\x00\x01\x01\x13"
|
||||
# Whether the NIC is connected to the network
|
||||
RNDIS_OID_GEN_MEDIA_CONNECT_STATUS="\x00\x01\x01\x14"
|
||||
# The maximum number of send packets the driver can accept per call to its MiniportSendPacketsfunction
|
||||
RNDIS_OID_GEN_MAXIMUM_SEND_PACKETS="\x00\x01\x01\x15"
|
||||
# Vendor-assigned version number of the driver
|
||||
RNDIS_OID_GEN_VENDOR_DRIVER_VERSION="\x00\x01\x01\x16"
|
||||
# The custom GUIDs (Globally Unique Identifier) supported by the miniport driver
|
||||
RNDIS_OID_GEN_SUPPORTED_GUIDS="\x00\x01\x01\x17"
|
||||
# List of network-layer addresses associated with the binding between a transport and the driver
|
||||
RNDIS_OID_GEN_NETWORK_LAYER_ADDRESSES="\x00\x01\x01\x18"
|
||||
# Size of packets' additional headers
|
||||
RNDIS_OID_GEN_TRANSPORT_HEADER_OFFSET="\x00\x01\x01\x19"
|
||||
RNDIS_OID_GEN_MEDIA_CAPABILITIES="\x00\x01\x02\x01"
|
||||
# Physical media supported by the miniport driver (encoded)
|
||||
RNDIS_OID_GEN_PHYSICAL_MEDIUM="\x00\x01\x02\x02"
|
||||
# Permanent station address
|
||||
RNDIS_OID_802_3_PERMANENT_ADDRESS="\x01\x01\x01\x01"
|
||||
# Current station address
|
||||
RNDIS_OID_802_3_CURRENT_ADDRESS="\x01\x01\x01\x02"
|
||||
# Current multicast address list
|
||||
RNDIS_OID_802_3_MULTICAST_LIST="\x01\x01\x01\x03"
|
||||
# Maximum size of multicast address list
|
||||
RNDIS_OID_802_3_MAXIMUM_LIST_SIZE="\x01\x01\x01\x04"
|
||||
# Directed packets. Directed packets contain a destination address equal to the station address of the NIC.
|
||||
RNDIS_PACKET_TYPE_DIRECTED="\x00\x00\x00\x01"
|
||||
# Multicast address packets sent to addresses in the multicast address list.
|
||||
RNDIS_PACKET_TYPE_MULTICAST="\x00\x00\x00\x02"
|
||||
# All multicast address packets, not just the ones enumerated in the multicast address list.
|
||||
RNDIS_PACKET_TYPE_ALL_MULTICAST="\x00\x00\x00\x04"
|
||||
# Broadcast packets.
|
||||
RNDIS_PACKET_TYPE_BROADCAST="\x00\x00\x00\x08"
|
||||
# All source routing packets. If the protocol driver sets this bit, the NDIS library attempts to act as a source routing bridge.
|
||||
RNDIS_PACKET_TYPE_SOURCE_ROUTING="\x00\x00\x00\x10"
|
||||
# Specifies all packets regardless of whether VLAN filtering is enabled or not and whether the VLAN identifier matches or not.
|
||||
RNDIS_PACKET_TYPE_PROMISCUOUS="\x00\x00\x00\x20"
|
||||
# SMT packets that an FDDI NIC receives.
|
||||
RNDIS_PACKET_TYPE_SMT="\x00\x00\x00\x40"
|
||||
# All packets sent by installed protocols and all packets indicated by the NIC that is identified by a given NdisBindingHandle.
|
||||
RNDIS_PACKET_TYPE_ALL_LOCAL="\x00\x00\x00\x80"
|
||||
# Packets sent to the current group address.
|
||||
RNDIS_PACKET_TYPE_GROUP="\x00\x00\x10\x00"
|
||||
# All functional address packets, not just the ones in the current functional address.
|
||||
RNDIS_PACKET_TYPE_ALL_FUNCTIONAL="\x00\x00\x20\x00"
|
||||
# Functional address packets sent to addresses included in the current functional address.
|
||||
RNDIS_PACKET_TYPE_FUNCTIONAL="\x00\x00\x40\x00"
|
||||
# NIC driver frames that a Token Ring NIC receives.
|
||||
RNDIS_PACKET_TYPE_MAC_FRAME="\x00\x00\x80\x00"
|
||||
RNDIS_PACKET_TYPE_NO_LOCAL="\x00\x01\x00\x00"
|
||||
34
managed_components/espressif__tinyusb/test/fuzz/fuzz.cc
Normal file
34
managed_components/espressif__tinyusb/test/fuzz/fuzz.cc
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Nathaniel Brough
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "fuzzer/FuzzedDataProvider.h"
|
||||
#include <optional>
|
||||
|
||||
std::optional<FuzzedDataProvider> _fuzz_data_provider;
|
||||
|
||||
extern "C" int fuzz_init(const uint8_t *data, size_t size) {
|
||||
_fuzz_data_provider.emplace(data, size);
|
||||
return 0;
|
||||
}
|
||||
37
managed_components/espressif__tinyusb/test/fuzz/fuzz.h
Normal file
37
managed_components/espressif__tinyusb/test/fuzz/fuzz.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Nathaniel Brough
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int fuzz_init(const uint8_t *data, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Nathaniel Brough
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "fuzzer/FuzzedDataProvider.h"
|
||||
#include <optional>
|
||||
|
||||
extern std::optional<FuzzedDataProvider> _fuzz_data_provider;
|
||||
128
managed_components/espressif__tinyusb/test/fuzz/make.mk
Normal file
128
managed_components/espressif__tinyusb/test/fuzz/make.mk
Normal file
@@ -0,0 +1,128 @@
|
||||
# ---------------------------------------
|
||||
# Common make definition for all examples
|
||||
# ---------------------------------------
|
||||
|
||||
#-------------- TOP and CURRENT_PATH ------------
|
||||
|
||||
# Set TOP to be the path to get from the current directory (where make was
|
||||
# invoked) to the top of the tree. $(lastword $(MAKEFILE_LIST)) returns
|
||||
# the name of this makefile relative to where make was invoked.
|
||||
THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST))
|
||||
|
||||
# strip off /tools/top.mk to get for example ../../..
|
||||
# and Set TOP to an absolute path
|
||||
TOP = $(abspath $(subst make.mk,../..,$(THIS_MAKEFILE)))
|
||||
|
||||
# Set CURRENT_PATH to the relative path from TOP to the current directory, ie examples/device/cdc_msc_freertos
|
||||
CURRENT_PATH = $(subst $(TOP)/,,$(abspath .))
|
||||
|
||||
# Detect whether shell style is windows or not
|
||||
# https://stackoverflow.com/questions/714100/os-detecting-makefile/52062069#52062069
|
||||
ifeq '$(findstring ;,$(PATH))' ';'
|
||||
# PATH contains semicolon - so we're definitely on Windows.
|
||||
CMDEXE := 1
|
||||
|
||||
# makefile shell commands should use syntax for DOS CMD, not unix sh
|
||||
# Unfortunately, SHELL may point to sh or bash, which can't accept DOS syntax.
|
||||
# We can't just use sh, because while sh and/or bash shell may be available,
|
||||
# many Windows environments won't have utilities like realpath used below, so...
|
||||
# Force DOS command shell on Windows.
|
||||
SHELL := cmd.exe
|
||||
endif
|
||||
|
||||
# Build directory
|
||||
BUILD := _build
|
||||
PROJECT := $(notdir $(CURDIR))
|
||||
|
||||
# Handy check parameter function
|
||||
check_defined = \
|
||||
$(strip $(foreach 1,$1, \
|
||||
$(call __check_defined,$1,$(strip $(value 2)))))
|
||||
__check_defined = \
|
||||
$(if $(value $1),, \
|
||||
$(error Undefined make flag: $1$(if $2, ($2))))
|
||||
|
||||
#-------------- Fuzz harness compiler ------------
|
||||
|
||||
CC ?= clang
|
||||
CXX ?= clang++
|
||||
GDB ?= gdb
|
||||
OBJCOPY = objcopy
|
||||
SIZE = size
|
||||
MKDIR = mkdir
|
||||
|
||||
ifeq ($(CMDEXE),1)
|
||||
CP = copy
|
||||
RM = del
|
||||
PYTHON = python
|
||||
else
|
||||
SED = sed
|
||||
CP = cp
|
||||
RM = rm
|
||||
PYTHON = python3
|
||||
endif
|
||||
|
||||
#-------------- Fuzz harness flags ------------
|
||||
COVERAGE_FLAGS ?= -fsanitize-coverage=trace-pc-guard
|
||||
SANITIZER_FLAGS ?= -fsanitize=fuzzer \
|
||||
-fsanitize=address
|
||||
|
||||
CFLAGS += $(COVERAGE_FLAGS) $(SANITIZER_FLAGS)
|
||||
|
||||
#-------------- Source files and compiler flags --------------
|
||||
INC += $(TOP)/test
|
||||
|
||||
# Compiler Flags
|
||||
CFLAGS += \
|
||||
-ggdb \
|
||||
-fdata-sections \
|
||||
-ffunction-sections \
|
||||
-fno-strict-aliasing \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Werror \
|
||||
-Wfatal-errors \
|
||||
-Wdouble-promotion \
|
||||
-Wstrict-prototypes \
|
||||
-Wstrict-overflow \
|
||||
-Werror-implicit-function-declaration \
|
||||
-Wfloat-equal \
|
||||
-Wundef \
|
||||
-Wshadow \
|
||||
-Wwrite-strings \
|
||||
-Wsign-compare \
|
||||
-Wmissing-format-attribute \
|
||||
-Wunreachable-code \
|
||||
-Wcast-align \
|
||||
-Wcast-qual \
|
||||
-Wnull-dereference \
|
||||
-Wuninitialized \
|
||||
-Wunused \
|
||||
-Wredundant-decls \
|
||||
-O1
|
||||
|
||||
CFLAGS += \
|
||||
-Wno-error=unreachable-code \
|
||||
-DOPT_MCU_FUZZ=1 \
|
||||
-DCFG_TUSB_MCU=OPT_MCU_FUZZ \
|
||||
-D_FUZZ
|
||||
|
||||
CXXFLAGS += \
|
||||
-xc++ \
|
||||
-Wno-c++11-narrowing \
|
||||
-fno-implicit-templates
|
||||
|
||||
# conversion is too strict for most mcu driver, may be disable sign/int/arith-conversion
|
||||
# -Wconversion
|
||||
|
||||
# Debugging/Optimization
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -Og
|
||||
else
|
||||
CFLAGS += $(CFLAGS_OPTIMIZED)
|
||||
endif
|
||||
|
||||
# Log level is mapped to TUSB DEBUG option
|
||||
ifneq ($(LOG),)
|
||||
CFLAGS += -DCFG_TUSB_DEBUG=$(LOG)
|
||||
endif
|
||||
162
managed_components/espressif__tinyusb/test/fuzz/msc_fuzz.cc
Normal file
162
managed_components/espressif__tinyusb/test/fuzz/msc_fuzz.cc
Normal file
@@ -0,0 +1,162 @@
|
||||
#include "fuzz/fuzz_private.h"
|
||||
#include "tusb.h"
|
||||
#include <cassert>
|
||||
#include <array>
|
||||
#include <limits>
|
||||
|
||||
#if CFG_TUD_MSC==1
|
||||
|
||||
// Whether host does safe eject.
|
||||
// tud_msc_get_maxlun_cb returns a uint8_t so the max logical units that are
|
||||
// allowed is 255, so we need to keep track of 255 fuzzed logical units.
|
||||
static std::array<bool, std::numeric_limits<uint8_t>::max()> ejected = {false};
|
||||
|
||||
extern "C" {
|
||||
// Invoked when received SCSI_CMD_INQUIRY
|
||||
// Application fill vendor id, product id and revision with string up to 8, 16,
|
||||
// 4 characters respectively
|
||||
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8],
|
||||
uint8_t product_id[16], uint8_t product_rev[4]) {
|
||||
(void)lun;
|
||||
assert(_fuzz_data_provider.has_value());
|
||||
|
||||
std::string vid = _fuzz_data_provider->ConsumeBytesAsString(8);
|
||||
std::string pid = _fuzz_data_provider->ConsumeBytesAsString(16);
|
||||
std::string rev = _fuzz_data_provider->ConsumeBytesAsString(4);
|
||||
|
||||
memcpy(vendor_id, vid.c_str(), strlen(vid.c_str()));
|
||||
memcpy(product_id, pid.c_str(), strlen(pid.c_str()));
|
||||
memcpy(product_rev, rev.c_str(), strlen(rev.c_str()));
|
||||
}
|
||||
|
||||
// Invoked when received Test Unit Ready command.
|
||||
// return true allowing host to read/write this LUN e.g SD card inserted
|
||||
bool tud_msc_test_unit_ready_cb(uint8_t lun) {
|
||||
// RAM disk is ready until ejected
|
||||
if (ejected[lun]) {
|
||||
// Additional Sense 3A-00 is NOT_FOUND
|
||||
tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00);
|
||||
return false;
|
||||
}
|
||||
|
||||
return _fuzz_data_provider->ConsumeBool();
|
||||
}
|
||||
|
||||
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and
|
||||
// SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size Application update
|
||||
// block count and block size
|
||||
void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count,
|
||||
uint16_t *block_size) {
|
||||
(void)lun;
|
||||
*block_count = _fuzz_data_provider->ConsumeIntegral<uint32_t>();
|
||||
*block_size = _fuzz_data_provider->ConsumeIntegral<uint16_t>();
|
||||
}
|
||||
|
||||
// Invoked when received Start Stop Unit command
|
||||
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
|
||||
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
|
||||
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start,
|
||||
bool load_eject) {
|
||||
(void)power_condition;
|
||||
assert(_fuzz_data_provider.has_value());
|
||||
|
||||
if (load_eject) {
|
||||
if (start) {
|
||||
// load disk storage
|
||||
} else {
|
||||
// unload disk storage
|
||||
ejected[lun] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return _fuzz_data_provider->ConsumeBool();
|
||||
}
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
|
||||
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset,
|
||||
void *buffer, uint32_t bufsize) {
|
||||
assert(_fuzz_data_provider.has_value());
|
||||
(void)lun;
|
||||
(void)lba;
|
||||
(void)offset;
|
||||
|
||||
std::vector<uint8_t> consumed_buffer = _fuzz_data_provider->ConsumeBytes<uint8_t>(
|
||||
_fuzz_data_provider->ConsumeIntegralInRange<uint32_t>(0, bufsize));
|
||||
memcpy(buffer, consumed_buffer.data(), consumed_buffer.size());
|
||||
|
||||
// Sometimes return an error code;
|
||||
if (_fuzz_data_provider->ConsumeBool()) {
|
||||
return _fuzz_data_provider->ConsumeIntegralInRange(
|
||||
std::numeric_limits<int32_t>::min(), -1);
|
||||
}
|
||||
|
||||
return consumed_buffer.size();
|
||||
}
|
||||
|
||||
bool tud_msc_is_writable_cb(uint8_t lun) {
|
||||
assert(_fuzz_data_provider.has_value());
|
||||
(void)lun;
|
||||
return _fuzz_data_provider->ConsumeBool();
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and return number of written bytes
|
||||
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset,
|
||||
uint8_t *buffer, uint32_t bufsize) {
|
||||
// Ignore these as they are outputs and don't affect the return value.
|
||||
(void)lun;
|
||||
(void)lba;
|
||||
(void)offset;
|
||||
(void)buffer;
|
||||
assert(_fuzz_data_provider.has_value());
|
||||
|
||||
// -ve error codes -> bufsize.
|
||||
return _fuzz_data_provider->ConsumeIntegralInRange<int32_t>(
|
||||
std::numeric_limits<int32_t>::min(), bufsize);
|
||||
}
|
||||
|
||||
// Callback invoked when received an SCSI command not in built-in list below
|
||||
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
|
||||
// - READ10 and WRITE10 has their own callbacks
|
||||
int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer,
|
||||
uint16_t bufsize) {
|
||||
(void)buffer;
|
||||
(void)bufsize;
|
||||
assert(_fuzz_data_provider.has_value());
|
||||
|
||||
switch (scsi_cmd[0]) {
|
||||
case SCSI_CMD_TEST_UNIT_READY:
|
||||
break;
|
||||
case SCSI_CMD_INQUIRY:
|
||||
break;
|
||||
case SCSI_CMD_MODE_SELECT_6:
|
||||
break;
|
||||
case SCSI_CMD_MODE_SENSE_6:
|
||||
break;
|
||||
case SCSI_CMD_START_STOP_UNIT:
|
||||
break;
|
||||
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
|
||||
break;
|
||||
case SCSI_CMD_READ_CAPACITY_10:
|
||||
break;
|
||||
case SCSI_CMD_REQUEST_SENSE:
|
||||
break;
|
||||
case SCSI_CMD_READ_FORMAT_CAPACITY:
|
||||
break;
|
||||
case SCSI_CMD_READ_10:
|
||||
break;
|
||||
case SCSI_CMD_WRITE_10:
|
||||
break;
|
||||
default:
|
||||
// Set Sense = Invalid Command Operation
|
||||
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
|
||||
return _fuzz_data_provider->ConsumeIntegralInRange<int32_t>(
|
||||
std::numeric_limits<int32_t>::min(), -1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
74
managed_components/espressif__tinyusb/test/fuzz/net_fuzz.cc
Normal file
74
managed_components/espressif__tinyusb/test/fuzz/net_fuzz.cc
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Nathaniel Brough
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tusb_config.h"
|
||||
#if defined(CFG_TUD_ECM_RNDIS) || defined(CFG_TUD_NCM)
|
||||
|
||||
#include "class/net/net_device.h"
|
||||
#include "fuzz_private.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include "lwip/sys.h"
|
||||
|
||||
extern "C" {
|
||||
bool tud_network_recv_cb(const uint8_t *src, uint16_t size) {
|
||||
assert(_fuzz_data_provider.has_value());
|
||||
(void)src;
|
||||
(void)size;
|
||||
return _fuzz_data_provider->ConsumeBool();
|
||||
}
|
||||
|
||||
// client must provide this: copy from network stack packet pointer to dst
|
||||
uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg) {
|
||||
(void)ref;
|
||||
(void)arg;
|
||||
|
||||
assert(_fuzz_data_provider.has_value());
|
||||
|
||||
uint16_t size = _fuzz_data_provider->ConsumeIntegral<uint16_t>();
|
||||
std::vector<uint8_t> temp = _fuzz_data_provider->ConsumeBytes<uint8_t>(size);
|
||||
memcpy(dst, temp.data(), temp.size());
|
||||
return size;
|
||||
}
|
||||
|
||||
/* lwip has provision for using a mutex, when applicable */
|
||||
sys_prot_t sys_arch_protect(void) { return 0; }
|
||||
void sys_arch_unprotect(sys_prot_t pval) { (void)pval; }
|
||||
|
||||
//------------- ECM/RNDIS -------------//
|
||||
|
||||
// client must provide this: initialize any network state back to the beginning
|
||||
void tud_network_init_cb(void) {
|
||||
// NoOp.
|
||||
}
|
||||
|
||||
// client must provide this: 48-bit MAC address
|
||||
// TODO removed later since it is not part of tinyusb stack
|
||||
uint8_t tud_network_mac_address[6] = {0};
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#endif
|
||||
160
managed_components/espressif__tinyusb/test/fuzz/rules.mk
Normal file
160
managed_components/espressif__tinyusb/test/fuzz/rules.mk
Normal file
@@ -0,0 +1,160 @@
|
||||
# ---------------------------------------
|
||||
# Common make rules for all examples
|
||||
# ---------------------------------------
|
||||
|
||||
# Set all as default goal
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
# ---------------------------------------
|
||||
# Compiler Flags
|
||||
# ---------------------------------------
|
||||
|
||||
LIBS_GCC ?= -lm
|
||||
|
||||
# libc
|
||||
LIBS += $(LIBS_GCC)
|
||||
|
||||
ifneq ($(BOARD), spresense)
|
||||
LIBS += -lc -Wl,-Bstatic -lc++ -Wl,-Bdynamic
|
||||
endif
|
||||
|
||||
# TinyUSB Stack source
|
||||
SRC_C += \
|
||||
src/tusb.c \
|
||||
src/common/tusb_fifo.c \
|
||||
src/device/usbd.c \
|
||||
src/device/usbd_control.c \
|
||||
src/class/audio/audio_device.c \
|
||||
src/class/cdc/cdc_device.c \
|
||||
src/class/dfu/dfu_device.c \
|
||||
src/class/dfu/dfu_rt_device.c \
|
||||
src/class/hid/hid_device.c \
|
||||
src/class/midi/midi_device.c \
|
||||
src/class/msc/msc_device.c \
|
||||
src/class/mtp/mtp_device.c \
|
||||
src/class/net/ecm_rndis_device.c \
|
||||
src/class/net/ncm_device.c \
|
||||
src/class/usbtmc/usbtmc_device.c \
|
||||
src/class/video/video_device.c \
|
||||
src/class/vendor/vendor_device.c
|
||||
|
||||
|
||||
# Fuzzers are c++
|
||||
SRC_CXX += \
|
||||
test/fuzz/dcd_fuzz.cc \
|
||||
test/fuzz/fuzz.cc \
|
||||
test/fuzz/msc_fuzz.cc \
|
||||
test/fuzz/net_fuzz.cc \
|
||||
test/fuzz/usbd_fuzz.cc
|
||||
|
||||
# TinyUSB stack include
|
||||
INC += $(TOP)/src
|
||||
|
||||
CFLAGS += $(addprefix -I,$(INC))
|
||||
CXXFLAGS += -std=c++17
|
||||
|
||||
# LTO makes it difficult to analyze map file for optimizing size purpose
|
||||
# We will run this option in ci
|
||||
ifeq ($(NO_LTO),1)
|
||||
CFLAGS := $(filter-out -flto,$(CFLAGS))
|
||||
endif
|
||||
|
||||
ifneq ($(LD_FILE),)
|
||||
LDFLAGS_LD_FILE ?= -Wl,-T,$(TOP)/$(LD_FILE)
|
||||
endif
|
||||
|
||||
LDFLAGS += $(CFLAGS) $(LDFLAGS_LD_FILE) -fuse-ld=lld -Wl,-Map=$@.map -Wl,--cref -Wl,-gc-sections
|
||||
ifneq ($(SKIP_NANOLIB), 1)
|
||||
endif
|
||||
|
||||
ASFLAGS += $(CFLAGS)
|
||||
|
||||
# Assembly files can be name with upper case .S, convert it to .s
|
||||
SRC_S := $(SRC_S:.S=.s)
|
||||
|
||||
# Due to GCC LTO bug https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966
|
||||
# assembly file should be placed first in linking order
|
||||
# '_asm' suffix is added to object of assembly file
|
||||
OBJ += $(addprefix $(BUILD)/obj/, $(SRC_S:.s=_asm.o))
|
||||
OBJ += $(addprefix $(BUILD)/obj/, $(SRC_C:.c=.o))
|
||||
OBJ += $(addprefix $(BUILD)/obj/, $(SRC_CXX:.cc=_cxx.o))
|
||||
|
||||
# Verbose mode
|
||||
ifeq ("$(V)","1")
|
||||
$(info CFLAGS $(CFLAGS) ) $(info )
|
||||
$(info LDFLAGS $(LDFLAGS)) $(info )
|
||||
$(info ASFLAGS $(ASFLAGS)) $(info )
|
||||
endif
|
||||
|
||||
# ---------------------------------------
|
||||
# Rules
|
||||
# ---------------------------------------
|
||||
|
||||
all: $(BUILD)/$(PROJECT)
|
||||
|
||||
OBJ_DIRS = $(sort $(dir $(OBJ)))
|
||||
$(OBJ): | $(OBJ_DIRS)
|
||||
$(OBJ_DIRS):
|
||||
ifeq ($(CMDEXE),1)
|
||||
@$(MKDIR) $(subst /,\,$@)
|
||||
else
|
||||
@$(MKDIR) -p $@
|
||||
endif
|
||||
|
||||
$(BUILD)/$(PROJECT): $(OBJ)
|
||||
@echo LINK $@
|
||||
@ $(CXX) -o $@ $(LIB_FUZZING_ENGINE) $^ $(LIBS) $(LDFLAGS)
|
||||
|
||||
# We set vpath to point to the top of the tree so that the source files
|
||||
# can be located. By following this scheme, it allows a single build rule
|
||||
# to be used to compile all .c files.
|
||||
vpath %.c . $(TOP)
|
||||
$(BUILD)/obj/%.o: %.c
|
||||
@echo CC $(notdir $@)
|
||||
@$(CC) $(CFLAGS) -c -MD -o $@ $<
|
||||
|
||||
# All cpp srcs
|
||||
vpath %.cc . $(TOP)
|
||||
$(BUILD)/obj/%_cxx.o: %.cc
|
||||
@echo CXX $(notdir $@)
|
||||
@$(CXX) $(CFLAGS) $(CXXFLAGS) -c -MD -o $@ $<
|
||||
|
||||
# ASM sources lower case .s
|
||||
vpath %.s . $(TOP)
|
||||
$(BUILD)/obj/%_asm.o: %.s
|
||||
@echo AS $(notdir $@)
|
||||
@$(CC) -x assembler-with-cpp $(ASFLAGS) -c -o $@ $<
|
||||
|
||||
# ASM sources upper case .S
|
||||
vpath %.S . $(TOP)
|
||||
$(BUILD)/obj/%_asm.o: %.S
|
||||
@echo AS $(notdir $@)
|
||||
@$(CC) -x assembler-with-cpp $(ASFLAGS) -c -o $@ $<
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
ifeq ($(CMDEXE),1)
|
||||
rd /S /Q $(subst /,\,$(BUILD))
|
||||
else
|
||||
$(RM) -rf $(BUILD)
|
||||
endif
|
||||
# ---------------- GNU Make End -----------------------
|
||||
|
||||
# get depenecies
|
||||
.PHONY: get-deps
|
||||
get-deps:
|
||||
$(PYTHON) $(TOP)/tools/get_deps.py $(FAMILY)
|
||||
|
||||
size: $(BUILD)/$(PROJECT)
|
||||
-@echo ''
|
||||
@$(SIZE) $<
|
||||
-@echo ''
|
||||
|
||||
# linkermap must be install previously at https://github.com/hathach/linkermap
|
||||
linkermap: $(BUILD)/$(PROJECT)
|
||||
@linkermap -v $<.map
|
||||
|
||||
# Print out the value of a make variable.
|
||||
# https://stackoverflow.com/questions/16467718/how-to-print-out-a-variable-in-makefile
|
||||
print-%:
|
||||
@echo $* = $($*)
|
||||
73
managed_components/espressif__tinyusb/test/fuzz/usbd_fuzz.cc
Normal file
73
managed_components/espressif__tinyusb/test/fuzz/usbd_fuzz.cc
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Nathaniel Brough
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "fuzz/fuzz_private.h"
|
||||
#include "tusb.h"
|
||||
// #include "usb_descriptors.h"
|
||||
|
||||
#ifndef CFG_FUZZ_MAX_STRING_LEN
|
||||
#define CFG_FUZZ_MAX_STRING_LEN 1000
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
||||
/* TODO: Implement a fuzzed version of this.
|
||||
uint8_t const *tud_descriptor_bos_cb(void) { }
|
||||
*/
|
||||
|
||||
/* TODO: Implement a fuzzed version of this.
|
||||
uint8_t const *tud_descriptor_device_qualifier_cb(void) {}
|
||||
*/
|
||||
|
||||
/* TODO: Implement a fuzzed version of this.
|
||||
uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) {}
|
||||
*/
|
||||
|
||||
void tud_mount_cb(void) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
void tud_umount_cb(void) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
void tud_suspend_cb(bool remote_wakeup_en) {
|
||||
(void)remote_wakeup_en;
|
||||
// NOOP
|
||||
}
|
||||
|
||||
void tud_resume_cb(void) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
/* TODO: Implement a fuzzed version of this.
|
||||
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage,
|
||||
tusb_control_request_t const *request) {}
|
||||
*/
|
||||
|
||||
/* TODO: Implement a fuzzed version of this.
|
||||
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {}
|
||||
*/
|
||||
}
|
||||
40
managed_components/espressif__tinyusb/test/hil/hfp.json
Normal file
40
managed_components/espressif__tinyusb/test/hil/hfp.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"boards": [
|
||||
{
|
||||
"name": "stm32l412nucleo",
|
||||
"uid": "41003B000E504E5457323020",
|
||||
"tests": {
|
||||
"device": true, "host": false, "dual": false
|
||||
},
|
||||
"flasher": {
|
||||
"name": "jlink",
|
||||
"uid": "774470029",
|
||||
"args": "-device STM32L412KB"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "stm32f746disco",
|
||||
"uid": "210041000C51343237303334",
|
||||
"tests": {
|
||||
"device": true, "host": false, "dual": false
|
||||
},
|
||||
"flasher": {
|
||||
"name": "jlink",
|
||||
"uid": "770935966",
|
||||
"args": "-device STM32F746NG"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "lpcxpresso43s67",
|
||||
"uid": "08F000044528BAAA8D858F58C50700F5",
|
||||
"tests": {
|
||||
"device": true, "host": false, "dual": false
|
||||
},
|
||||
"flasher": {
|
||||
"name": "jlink",
|
||||
"uid": "728973776",
|
||||
"args": "-device LPC43S67_M4"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('config_file', help='Configuration JSON file')
|
||||
args = parser.parse_args()
|
||||
|
||||
config_file = args.config_file
|
||||
|
||||
# if config file is not found, try to find it in the same directory as this script
|
||||
if not os.path.exists(config_file):
|
||||
config_file = os.path.join(os.path.dirname(__file__), config_file)
|
||||
with open(config_file) as f:
|
||||
config = json.load(f)
|
||||
|
||||
matrix = {
|
||||
'arm-gcc': [],
|
||||
'esp-idf': []
|
||||
}
|
||||
for board in config['boards']:
|
||||
name = board['name']
|
||||
flasher = board['flasher']
|
||||
if flasher['name'] == 'esptool':
|
||||
toolchain = 'esp-idf'
|
||||
else:
|
||||
toolchain = 'arm-gcc'
|
||||
|
||||
build_board = f'-b {name}'
|
||||
if 'build' in board:
|
||||
if 'args' in board['build']:
|
||||
build_board += ' ' + ' '.join(f'-D{a}' for a in board['build']['args'])
|
||||
if 'flags_on' in board['build']:
|
||||
for f in board['build']['flags_on']:
|
||||
if f == '':
|
||||
matrix[toolchain].append(build_board)
|
||||
else:
|
||||
matrix[toolchain].append(f'{build_board} -f1 {f.replace(" ", " -f1 ")}')
|
||||
else:
|
||||
matrix[toolchain].append(build_board)
|
||||
else:
|
||||
matrix[toolchain].append(build_board)
|
||||
|
||||
print(json.dumps(matrix))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
753
managed_components/espressif__tinyusb/test/hil/hil_test.py
Normal file
753
managed_components/espressif__tinyusb/test/hil/hil_test.py
Normal file
@@ -0,0 +1,753 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2023 HiFiPhile
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
# udev rules :
|
||||
# ACTION=="add", SUBSYSTEM=="tty", SUBSYSTEMS=="usb", MODE="0666", PROGRAM="/bin/sh -c 'echo $$ID_SERIAL_SHORT | rev | cut -c -8 | rev'", SYMLINK+="ttyUSB_%c.%s{bInterfaceNumber}"
|
||||
# ACTION=="add", SUBSYSTEM=="block", SUBSYSTEMS=="usb", ENV{ID_FS_USAGE}=="filesystem", MODE="0666", PROGRAM="/bin/sh -c 'echo $$ID_SERIAL_SHORT | rev | cut -c -8 | rev'", RUN{program}+="/usr/bin/systemd-mount --no-block --automount=yes --collect $devnode /media/blkUSB_%c.%s{bInterfaceNumber}"
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import serial
|
||||
import subprocess
|
||||
import json
|
||||
import glob
|
||||
from multiprocessing import Pool
|
||||
import fs
|
||||
import hashlib
|
||||
import ctypes
|
||||
from pymtp import MTP
|
||||
|
||||
ENUM_TIMEOUT = 30
|
||||
|
||||
STATUS_OK = "\033[32mOK\033[0m"
|
||||
STATUS_FAILED = "\033[31mFailed\033[0m"
|
||||
STATUS_SKIPPED = "\033[33mSkipped\033[0m"
|
||||
|
||||
verbose = False
|
||||
test_only = []
|
||||
|
||||
WCH_RISCV_CONTENT = """
|
||||
adapter driver wlinke
|
||||
adapter speed 6000
|
||||
transport select sdi
|
||||
|
||||
wlink_set_address 0x00000000
|
||||
set _CHIPNAME wch_riscv
|
||||
sdi newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00001
|
||||
|
||||
set _TARGETNAME $_CHIPNAME.cpu
|
||||
|
||||
target create $_TARGETNAME.0 wch_riscv -chain-position $_TARGETNAME
|
||||
$_TARGETNAME.0 configure -work-area-phys 0x20000000 -work-area-size 10000 -work-area-backup 1
|
||||
set _FLASHNAME $_CHIPNAME.flash
|
||||
|
||||
flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0
|
||||
|
||||
echo "Ready for Remote Connections"
|
||||
"""
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Path
|
||||
# -------------------------------------------------------------
|
||||
OPENCOD_ADI_PATH = f'{os.getenv("HOME")}/app/openocd_adi'
|
||||
TINYUSB_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
# get usb serial by id
|
||||
def get_serial_dev(id, vendor_str, product_str, ifnum):
|
||||
if vendor_str and product_str:
|
||||
# known vendor and product
|
||||
vendor_str = vendor_str.replace(' ', '_')
|
||||
product_str = product_str.replace(' ', '_')
|
||||
return f'/dev/serial/by-id/usb-{vendor_str}_{product_str}_{id}-if{ifnum:02d}'
|
||||
else:
|
||||
# just use id: mostly for cp210x/ftdi flasher
|
||||
pattern = f'/dev/serial/by-id/usb-*_{id}-if*'
|
||||
port_list = glob.glob(pattern)
|
||||
return port_list[0]
|
||||
|
||||
|
||||
# get usb disk by id
|
||||
def get_disk_dev(id, vendor_str, lun):
|
||||
return f'/dev/disk/by-id/usb-{vendor_str}_Mass_Storage_{id}-0:{lun}'
|
||||
|
||||
|
||||
def get_hid_dev(id, vendor_str, product_str, event):
|
||||
return f'/dev/input/by-id/usb-{vendor_str}_{product_str}_{id}-{event}'
|
||||
|
||||
|
||||
def open_serial_dev(port):
|
||||
timeout = ENUM_TIMEOUT
|
||||
ser = None
|
||||
while timeout > 0:
|
||||
if os.path.exists(port):
|
||||
try:
|
||||
ser = serial.Serial(port, baudrate=115200, timeout=5)
|
||||
break
|
||||
except serial.SerialException:
|
||||
print(f'serial {port} not reaady {timeout} sec')
|
||||
pass
|
||||
time.sleep(0.1)
|
||||
timeout -= 0.1
|
||||
|
||||
assert timeout > 0, f'Cannot open port f{port}' if os.path.exists(port) else f'Port {port} not existed'
|
||||
return ser
|
||||
|
||||
|
||||
def read_disk_file(uid, lun, fname):
|
||||
# open_fs("fat://{dev}) require 'pip install pyfatfs'
|
||||
dev = get_disk_dev(uid, 'TinyUSB', lun)
|
||||
timeout = ENUM_TIMEOUT
|
||||
while timeout > 0:
|
||||
if os.path.exists(dev):
|
||||
fat = fs.open_fs(f'fat://{dev}?read_only=true')
|
||||
try:
|
||||
with fat.open(fname, 'rb') as f:
|
||||
data = f.read()
|
||||
finally:
|
||||
fat.close()
|
||||
assert data, f'Cannot read file {fname} from {dev}'
|
||||
return data
|
||||
time.sleep(1)
|
||||
timeout -= 1
|
||||
|
||||
assert timeout > 0, f'Storage {dev} not existed'
|
||||
return None
|
||||
|
||||
|
||||
def open_mtp_dev(uid):
|
||||
mtp = MTP()
|
||||
timeout = ENUM_TIMEOUT
|
||||
while timeout > 0:
|
||||
# run_cmd(f"gio mount -u mtp://TinyUsb_TinyUsb_Device_{uid}/")
|
||||
for raw in mtp.detect_devices():
|
||||
mtp.device = mtp.mtp.LIBMTP_Open_Raw_Device(ctypes.byref(raw))
|
||||
if mtp.device:
|
||||
sn = mtp.get_serialnumber().decode('utf-8')
|
||||
#print(f'mtp serial = {sn}')
|
||||
if sn == uid:
|
||||
return mtp
|
||||
time.sleep(1)
|
||||
timeout -= 1
|
||||
return None
|
||||
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Flashing firmware
|
||||
# -------------------------------------------------------------
|
||||
def run_cmd(cmd, cwd=None):
|
||||
r = subprocess.run(cmd, cwd=cwd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
if r.returncode != 0:
|
||||
title = f'COMMAND FAILED: {cmd}'
|
||||
print()
|
||||
if os.getenv('CI'):
|
||||
print(f"::group::{title}")
|
||||
print(r.stdout.decode("utf-8"))
|
||||
print(f"::endgroup::")
|
||||
else:
|
||||
print(title)
|
||||
print(r.stdout.decode("utf-8"))
|
||||
elif verbose:
|
||||
print(cmd)
|
||||
print(r.stdout.decode("utf-8"))
|
||||
return r
|
||||
|
||||
|
||||
def flash_jlink(board, firmware):
|
||||
flasher = board['flasher']
|
||||
script = ['halt', 'r', f'loadfile {firmware}.elf', 'r', 'go', 'exit']
|
||||
f_jlink = f'{board["name"]}_{os.path.basename(firmware)}.jlink'
|
||||
with open(f_jlink, 'w') as f:
|
||||
f.writelines(f'{s}\n' for s in script)
|
||||
ret = run_cmd(f'JLinkExe -USB {flasher["uid"]} {flasher["args"]} -if swd -JTAGConf -1,-1 -speed auto -NoGui 1 -ExitOnError 1 -CommandFile {f_jlink}')
|
||||
os.remove(f_jlink)
|
||||
return ret
|
||||
|
||||
|
||||
def reset_jlink(board):
|
||||
flasher = board['flasher']
|
||||
script = ['halt', 'r', 'go', 'exit']
|
||||
f_jlink = f'{board["name"]}_reset.jlink'
|
||||
if not os.path.exists(f_jlink):
|
||||
with open(f_jlink, 'w') as f:
|
||||
f.writelines(f'{s}\n' for s in script)
|
||||
ret = run_cmd(f'JLinkExe -USB {flasher["uid"]} {flasher["args"]} -if swd -JTAGConf -1,-1 -speed auto -NoGui 1 -ExitOnError 1 -CommandFile {f_jlink}')
|
||||
return ret
|
||||
|
||||
|
||||
def flash_stlink(board, firmware):
|
||||
flasher = board['flasher']
|
||||
return run_cmd(f'STM32_Programmer_CLI --connect port=swd sn={flasher["uid"]} --write {firmware}.elf --go')
|
||||
|
||||
|
||||
def reset_stlink(board):
|
||||
flasher = board['flasher']
|
||||
return run_cmd(f'STM32_Programmer_CLI --connect port=swd sn={flasher["uid"]} --rst --go')
|
||||
|
||||
def flash_stflash(board, firmware):
|
||||
flasher = board['flasher']
|
||||
ret = run_cmd(f'st-flash --serial {flasher["uid"]} write {firmware}.bin 0x8000000')
|
||||
return ret
|
||||
|
||||
|
||||
def reset_stflash(board):
|
||||
flasher = board['flasher']
|
||||
return subprocess.CompletedProcess(args=['dummy'], returncode=0)
|
||||
|
||||
|
||||
def flash_openocd(board, firmware):
|
||||
flasher = board['flasher']
|
||||
ret = run_cmd(f'openocd -c "tcl_port disabled" -c "gdb_port disabled" -c "adapter serial {flasher["uid"]}" '
|
||||
f'{flasher["args"]} -c "init; halt; program {firmware}.elf verify; reset; exit"')
|
||||
return ret
|
||||
|
||||
|
||||
def reset_openocd(board):
|
||||
flasher = board['flasher']
|
||||
ret = run_cmd(f'openocd -c "tcl_port disabled" -c "gdb_port disabled" -c "adapter serial {flasher["uid"]}" '
|
||||
f'{flasher["args"]} -c "init; reset run; exit"')
|
||||
return ret
|
||||
|
||||
|
||||
def flash_openocd_wch(board, firmware):
|
||||
flasher = board['flasher']
|
||||
f_wch = f"wch-riscv_{board['uid']}.cfg"
|
||||
if not os.path.exists(f_wch):
|
||||
with open(f_wch, 'w') as file:
|
||||
file.write(WCH_RISCV_CONTENT)
|
||||
|
||||
ret = run_cmd(f'openocd_wch -c "adapter serial {flasher["uid"]}" -f {f_wch} '
|
||||
f'-c "program {firmware}.elf reset exit"')
|
||||
return ret
|
||||
|
||||
|
||||
def reset_openocd_wch(board):
|
||||
flasher = board['flasher']
|
||||
f_wch = f"wch-riscv_{board['uid']}.cfg"
|
||||
if not os.path.exists(f_wch):
|
||||
with open(f_wch, 'w') as file:
|
||||
file.write(WCH_RISCV_CONTENT)
|
||||
|
||||
ret = run_cmd(f'openocd_wch -c "adapter serial {flasher["uid"]}" -f {f_wch} -c "program reset exit"')
|
||||
return ret
|
||||
|
||||
|
||||
def flash_openocd_adi(board, firmware):
|
||||
flasher = board['flasher']
|
||||
ret = run_cmd(f'{OPENCOD_ADI_PATH}/src/openocd -c "adapter serial {flasher["uid"]}" -s {OPENCOD_ADI_PATH}/tcl '
|
||||
f'{flasher["args"]} -c "program {firmware}.elf reset exit"')
|
||||
return ret
|
||||
|
||||
|
||||
def reset_openocd_adi(board):
|
||||
flasher = board['flasher']
|
||||
ret = run_cmd(f'{OPENCOD_ADI_PATH}/src/openocd -c "adapter serial {flasher["uid"]}" -s {OPENCOD_ADI_PATH}/tcl '
|
||||
f'{flasher["args"]} -c "program reset exit"')
|
||||
return ret
|
||||
|
||||
|
||||
def flash_wlink_rs(board, firmware):
|
||||
flasher = board['flasher']
|
||||
# wlink use index for probe selection and lacking usb serial support
|
||||
ret = run_cmd(f'wlink flash {firmware}.elf')
|
||||
return ret
|
||||
|
||||
|
||||
def reset_wlink_rs(board):
|
||||
flasher = board['flasher']
|
||||
# wlink use index for probe selection and lacking usb serial support
|
||||
ret = run_cmd(f'wlink reset')
|
||||
return ret
|
||||
|
||||
|
||||
def flash_esptool(board, firmware):
|
||||
flasher = board['flasher']
|
||||
port = get_serial_dev(flasher["uid"], None, None, 0)
|
||||
fw_dir = os.path.dirname(f'{firmware}.bin')
|
||||
with open(f'{fw_dir}/config.env') as f:
|
||||
idf_target = json.load(f)['IDF_TARGET']
|
||||
with open(f'{fw_dir}/flash_args') as f:
|
||||
flash_args = f.read().strip().replace('\n', ' ')
|
||||
command = (f'esptool.py --chip {idf_target} -p {port} {flasher["args"]} '
|
||||
f'--before=default_reset --after=hard_reset write_flash {flash_args}')
|
||||
ret = run_cmd(command, cwd=fw_dir)
|
||||
return ret
|
||||
|
||||
|
||||
def reset_esptool(board):
|
||||
flasher = board['flasher']
|
||||
return subprocess.CompletedProcess(args=['dummy'], returncode=0)
|
||||
|
||||
|
||||
def flash_uniflash(board, firmware):
|
||||
flasher = board['flasher']
|
||||
ret = run_cmd(f'dslite.sh {flasher["args"]} -f {firmware}.hex')
|
||||
return ret
|
||||
|
||||
|
||||
def reset_uniflash(board):
|
||||
flasher = board['flasher']
|
||||
return subprocess.CompletedProcess(args=['dummy'], returncode=0)
|
||||
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Tests: dual
|
||||
# -------------------------------------------------------------
|
||||
def test_dual_host_info_to_device_cdc(board):
|
||||
uid = board['uid']
|
||||
declared_devs = [f'{d["vid_pid"]}_{d["serial"]}' for d in board['tests']['dev_attached']]
|
||||
port = get_serial_dev(uid, 'TinyUSB', "TinyUSB_Device", 0)
|
||||
ser = open_serial_dev(port)
|
||||
|
||||
# read from cdc, first line should contain vid/pid and serial
|
||||
data = ser.read(10000)
|
||||
ser.close()
|
||||
if len(data) == 0:
|
||||
assert False, 'No data from device'
|
||||
lines = data.decode('utf-8', errors='ignore').splitlines()
|
||||
|
||||
enum_dev_sn = []
|
||||
for l in lines:
|
||||
vid_pid_sn = re.search(r'ID ([0-9a-fA-F]+):([0-9a-fA-F]+) SN (\w+)', l)
|
||||
if vid_pid_sn:
|
||||
print(f'\r\n {l} ', end='')
|
||||
enum_dev_sn.append(f'{vid_pid_sn.group(1)}_{vid_pid_sn.group(2)}_{vid_pid_sn.group(3)}')
|
||||
|
||||
if set(declared_devs) != set(enum_dev_sn):
|
||||
failed_msg = f'Expected {declared_devs}, Enumerated {enum_dev_sn}'
|
||||
print('\n'.join(lines))
|
||||
assert False, failed_msg
|
||||
return 0
|
||||
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Tests: host
|
||||
# -------------------------------------------------------------
|
||||
def test_host_device_info(board):
|
||||
flasher = board['flasher']
|
||||
declared_devs = [f'{d["vid_pid"]}_{d["serial"]}' for d in board['tests']['dev_attached']]
|
||||
|
||||
port = get_serial_dev(flasher["uid"], None, None, 0)
|
||||
ser = open_serial_dev(port)
|
||||
|
||||
# reset device since we can miss the first line
|
||||
ret = globals()[f'reset_{flasher["name"].lower()}'](board)
|
||||
assert ret.returncode == 0, 'Failed to reset device'
|
||||
|
||||
data = ser.read(10000)
|
||||
ser.close()
|
||||
if len(data) == 0:
|
||||
assert False, 'No data from device'
|
||||
lines = data.decode('utf-8', errors='ignore').splitlines()
|
||||
|
||||
enum_dev_sn = []
|
||||
for l in lines:
|
||||
vid_pid_sn = re.search(r'ID ([0-9a-fA-F]+):([0-9a-fA-F]+) SN (\w+)', l)
|
||||
if vid_pid_sn:
|
||||
print(f'\r\n {l} ', end='')
|
||||
enum_dev_sn.append(f'{vid_pid_sn.group(1)}_{vid_pid_sn.group(2)}_{vid_pid_sn.group(3)}')
|
||||
|
||||
if set(declared_devs) != set(enum_dev_sn):
|
||||
failed_msg = f'Expected {declared_devs}, Enumerated {enum_dev_sn}'
|
||||
print('\n'.join(lines))
|
||||
assert False, failed_msg
|
||||
return 0
|
||||
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Tests: device
|
||||
# -------------------------------------------------------------
|
||||
def test_device_board_test(board):
|
||||
# Dummy test
|
||||
pass
|
||||
|
||||
|
||||
def test_device_cdc_dual_ports(board):
|
||||
uid = board['uid']
|
||||
port = [
|
||||
get_serial_dev(uid, 'TinyUSB', "TinyUSB_Device", 0),
|
||||
get_serial_dev(uid, 'TinyUSB', "TinyUSB_Device", 2)
|
||||
]
|
||||
ser = [open_serial_dev(p) for p in port]
|
||||
|
||||
str_test = [ b"test_no1", b"test_no2" ]
|
||||
# Echo test write to each port and read back
|
||||
for i in range(len(str_test)):
|
||||
s = str_test[i]
|
||||
l = len(s)
|
||||
ser[i].write(s)
|
||||
ser[i].flush()
|
||||
rd = [ ser[i].read(l) for i in range(len(ser)) ]
|
||||
assert rd[0] == s.lower(), f'Port1 wrong data: expected {s.lower()} was {rd[0]}'
|
||||
assert rd[1] == s.upper(), f'Port2 wrong data: expected {s.upper()} was {rd[1]}'
|
||||
ser[0].close()
|
||||
ser[1].close()
|
||||
|
||||
|
||||
def test_device_cdc_msc(board):
|
||||
uid = board['uid']
|
||||
# Echo test
|
||||
port = get_serial_dev(uid, 'TinyUSB', "TinyUSB_Device", 0)
|
||||
ser = open_serial_dev(port)
|
||||
|
||||
test_str = b"test_str"
|
||||
ser.write(test_str)
|
||||
ser.flush()
|
||||
rd_str = ser.read(len(test_str))
|
||||
ser.close()
|
||||
assert rd_str == test_str, f'CDC wrong data: expected: {test_str} was {rd_str}'
|
||||
|
||||
# Block test
|
||||
data = read_disk_file(uid,0,'README.TXT')
|
||||
readme = \
|
||||
b"This is tinyusb's MassStorage Class demo.\r\n\r\n\
|
||||
If you find any bugs or get any questions, feel free to file an\r\n\
|
||||
issue at github.com/hathach/tinyusb"
|
||||
|
||||
assert data == readme, 'MSC wrong data'
|
||||
|
||||
|
||||
def test_device_cdc_msc_freertos(board):
|
||||
test_device_cdc_msc(board)
|
||||
|
||||
|
||||
def test_device_dfu(board):
|
||||
uid = board['uid']
|
||||
|
||||
# Wait device enum
|
||||
timeout = ENUM_TIMEOUT
|
||||
while timeout > 0:
|
||||
ret = run_cmd(f'dfu-util -l')
|
||||
stdout = ret.stdout.decode()
|
||||
if f'serial="{uid}"' in stdout and 'Found DFU: [cafe:4000]' in stdout:
|
||||
break
|
||||
time.sleep(1)
|
||||
timeout = timeout - 1
|
||||
|
||||
assert timeout > 0, 'Device not available'
|
||||
|
||||
f_dfu0 = f'dfu0_{uid}'
|
||||
f_dfu1 = f'dfu1_{uid}'
|
||||
|
||||
# Test upload
|
||||
try:
|
||||
os.remove(f_dfu0)
|
||||
os.remove(f_dfu1)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
ret = run_cmd(f'dfu-util -S {uid} -a 0 -U {f_dfu0}')
|
||||
assert ret.returncode == 0, 'Upload failed'
|
||||
|
||||
ret = run_cmd(f'dfu-util -S {uid} -a 1 -U {f_dfu1}')
|
||||
assert ret.returncode == 0, 'Upload failed'
|
||||
|
||||
with open(f_dfu0) as f:
|
||||
assert 'Hello world from TinyUSB DFU! - Partition 0' in f.read(), 'Wrong uploaded data'
|
||||
|
||||
with open(f_dfu1) as f:
|
||||
assert 'Hello world from TinyUSB DFU! - Partition 1' in f.read(), 'Wrong uploaded data'
|
||||
|
||||
os.remove(f_dfu0)
|
||||
os.remove(f_dfu1)
|
||||
|
||||
|
||||
def test_device_dfu_runtime(board):
|
||||
uid = board['uid']
|
||||
# Wait device enum
|
||||
timeout = ENUM_TIMEOUT
|
||||
while timeout > 0:
|
||||
ret = run_cmd(f'dfu-util -l')
|
||||
stdout = ret.stdout.decode()
|
||||
if f'serial="{uid}"' in stdout and 'Found Runtime: [cafe:4000]' in stdout:
|
||||
break
|
||||
time.sleep(1)
|
||||
timeout = timeout - 1
|
||||
|
||||
assert timeout > 0, 'Device not available'
|
||||
|
||||
|
||||
def test_device_hid_boot_interface(board):
|
||||
uid = board['uid']
|
||||
kbd = get_hid_dev(uid, 'TinyUSB', 'TinyUSB_Device', 'event-kbd')
|
||||
mouse1 = get_hid_dev(uid, 'TinyUSB', 'TinyUSB_Device', 'if01-event-mouse')
|
||||
mouse2 = get_hid_dev(uid, 'TinyUSB', 'TinyUSB_Device', 'if01-mouse')
|
||||
# Wait device enum
|
||||
timeout = ENUM_TIMEOUT
|
||||
while timeout > 0:
|
||||
if os.path.exists(kbd) and os.path.exists(mouse1) and os.path.exists(mouse2):
|
||||
break
|
||||
time.sleep(1)
|
||||
timeout = timeout - 1
|
||||
|
||||
assert timeout > 0, 'HID device not available'
|
||||
|
||||
|
||||
def test_device_hid_composite_freertos(id):
|
||||
# TODO implement later
|
||||
pass
|
||||
|
||||
|
||||
def test_device_mtp(board):
|
||||
uid = board['uid']
|
||||
|
||||
# --- BEFORE: mute C-level stderr for libmtp vid/pid warnings ---
|
||||
fd = sys.stderr.fileno()
|
||||
_saved = os.dup(fd)
|
||||
_null = os.open(os.devnull, os.O_WRONLY)
|
||||
os.dup2(_null, fd)
|
||||
|
||||
mtp = open_mtp_dev(uid)
|
||||
|
||||
# --- AFTER: restore stderr ---
|
||||
os.dup2(_saved, fd)
|
||||
os.close(_null)
|
||||
os.close(_saved)
|
||||
|
||||
if mtp is None or mtp.device is None:
|
||||
assert False, 'MTP device not found'
|
||||
|
||||
try:
|
||||
assert b"TinyUSB" == mtp.get_manufacturer(), 'MTP wrong manufacturer'
|
||||
assert b"MTP Example" == mtp.get_modelname(), 'MTP wrong model'
|
||||
assert b'1.0' == mtp.get_deviceversion(), 'MTP wrong version'
|
||||
assert b'TinyUSB MTP' == mtp.get_devicename(), 'MTP wrong device name'
|
||||
|
||||
# read and compare readme.txt and logo.png
|
||||
f1_expect = b'TinyUSB MTP Filesystem example'
|
||||
f2_md5_expect = '40ef23fc2891018d41a05d4a0d5f822f' # md5sum of logo.png
|
||||
f1 = uid.encode("utf-8") + b'_file1'
|
||||
f2 = uid.encode("utf-8") + b'_file2'
|
||||
f3 = uid.encode("utf-8") + b'_file3'
|
||||
mtp.get_file_to_file(1, f1)
|
||||
with open(f1, 'rb') as file:
|
||||
f1_data = file.read()
|
||||
os.remove(f1)
|
||||
assert f1_data == f1_expect, 'MTP file1 wrong data'
|
||||
mtp.get_file_to_file(2, f2)
|
||||
with open(f2, 'rb') as file:
|
||||
f2_data = file.read()
|
||||
os.remove(f2)
|
||||
assert f2_md5_expect == hashlib.md5(f2_data).hexdigest(), 'MTP file2 wrong data'
|
||||
# test send file
|
||||
with open(f3, "wb") as file:
|
||||
f3_data = os.urandom(random.randint(1024, 3*1024))
|
||||
file.write(f3_data)
|
||||
file.close()
|
||||
fid = mtp.send_file_from_file(f3, b'file3')
|
||||
f3_readback = f3 + b'_readback'
|
||||
mtp.get_file_to_file(fid, f3_readback)
|
||||
with open(f3_readback, 'rb') as f:
|
||||
f3_rb_data = f.read()
|
||||
os.remove(f3_readback)
|
||||
assert f3_rb_data == f3_data, 'MTP file3 wrong data'
|
||||
os.remove(f3)
|
||||
mtp.delete_object(fid)
|
||||
finally:
|
||||
mtp.disconnect()
|
||||
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Main
|
||||
# -------------------------------------------------------------
|
||||
# device tests
|
||||
# note don't test 2 examples with cdc or 2 msc next to each other
|
||||
device_tests = [
|
||||
'device/cdc_dual_ports',
|
||||
'device/dfu',
|
||||
'device/cdc_msc',
|
||||
'device/dfu_runtime',
|
||||
'device/cdc_msc_freertos',
|
||||
'device/hid_boot_interface',
|
||||
'device/mtp'
|
||||
]
|
||||
|
||||
dual_tests = [
|
||||
'dual/host_info_to_device_cdc',
|
||||
]
|
||||
|
||||
host_test = [
|
||||
'host/device_info',
|
||||
]
|
||||
|
||||
|
||||
def test_example(board, f1, example):
|
||||
"""
|
||||
Test example firmware
|
||||
:param board: board dict
|
||||
:param f1: flags on
|
||||
:param example: example name
|
||||
:return: 0 if success/skip, 1 if failed
|
||||
"""
|
||||
name = board['name']
|
||||
err_count = 0
|
||||
|
||||
f1_str = ""
|
||||
if f1 != "":
|
||||
f1_str = '-f1_' + f1.replace(' ', '_')
|
||||
|
||||
fw_dir = f'{TINYUSB_ROOT}/cmake-build/cmake-build-{name}{f1_str}/{example}'
|
||||
if not os.path.exists(fw_dir):
|
||||
fw_dir = f'{TINYUSB_ROOT}/examples/cmake-build-{name}{f1_str}/{example}'
|
||||
fw_name = f'{fw_dir}/{os.path.basename(example)}'
|
||||
print(f'{name+f1_str:40} {example:30} ...', end='')
|
||||
|
||||
if not os.path.exists(fw_dir) or not (os.path.exists(f'{fw_name}.elf') or os.path.exists(f'{fw_name}.bin')):
|
||||
print('Skip (no binary)')
|
||||
return 0
|
||||
|
||||
if verbose:
|
||||
print(f'Flashing {fw_name}.elf')
|
||||
|
||||
# flash firmware. It may fail randomly, retry a few times
|
||||
max_rety = 3
|
||||
start_s = time.time()
|
||||
for i in range(max_rety):
|
||||
ret = globals()[f'flash_{board["flasher"]["name"].lower()}'](board, fw_name)
|
||||
if ret.returncode == 0:
|
||||
try:
|
||||
globals()[f'test_{example.replace("/", "_")}'](board)
|
||||
print(' OK', end='')
|
||||
break
|
||||
except Exception as e:
|
||||
if i == max_rety - 1:
|
||||
err_count += 1
|
||||
print(f'{STATUS_FAILED}: {e}')
|
||||
else:
|
||||
print(f'\n Test failed: {e}, retry {i+2}/{max_rety}', end='')
|
||||
time.sleep(0.5)
|
||||
else:
|
||||
print(f'\n Flash failed, retry {i+2}/{max_rety}', end='')
|
||||
time.sleep(0.5)
|
||||
|
||||
if ret.returncode != 0:
|
||||
err_count += 1
|
||||
print(f' Flash {STATUS_FAILED}', end='')
|
||||
|
||||
print(f' in {time.time() - start_s:.1f}s')
|
||||
|
||||
return err_count
|
||||
|
||||
|
||||
def test_board(board):
|
||||
name = board['name']
|
||||
flasher = board['flasher']
|
||||
|
||||
# default to all tests
|
||||
test_list = []
|
||||
|
||||
if len(test_only) > 0:
|
||||
test_list = test_only
|
||||
else:
|
||||
if 'tests' in board:
|
||||
board_tests = board['tests']
|
||||
if 'device' in board_tests and board_tests['device'] == True:
|
||||
test_list += list(device_tests)
|
||||
if 'dual' in board_tests and board_tests['dual'] == True:
|
||||
test_list += dual_tests
|
||||
if 'host' in board_tests and board_tests['host'] == True:
|
||||
test_list += host_test
|
||||
if 'only' in board_tests:
|
||||
test_list = board_tests['only']
|
||||
if 'skip' in board_tests:
|
||||
for skip in board_tests['skip']:
|
||||
if skip in test_list:
|
||||
test_list.remove(skip)
|
||||
print(f'{name:25} {skip:30} ... Skip')
|
||||
|
||||
err_count = 0
|
||||
flags_on_list = [""]
|
||||
if 'build' in board and 'flags_on' in board['build']:
|
||||
flags_on_list = board['build']['flags_on']
|
||||
|
||||
for f1 in flags_on_list:
|
||||
for test in test_list:
|
||||
err_count += test_example(board, f1, test)
|
||||
|
||||
# flash board_test last to disable board's usb
|
||||
test_example(board, flags_on_list[0], 'device/board_test')
|
||||
|
||||
return name, err_count
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Hardware test on specified boards
|
||||
"""
|
||||
global verbose
|
||||
global test_only
|
||||
|
||||
duration = time.time()
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('config_file', help='Configuration JSON file')
|
||||
parser.add_argument('-b', '--board', action='append', default=[], help='Boards to test, all if not specified')
|
||||
parser.add_argument('-s', '--skip', action='append', default=[], help='Skip boards from test')
|
||||
parser.add_argument('-t', '--test-only', action='append', default=[], help='Tests to run, all if not specified')
|
||||
parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
|
||||
args = parser.parse_args()
|
||||
|
||||
config_file = args.config_file
|
||||
boards = args.board
|
||||
skip_boards = args.skip
|
||||
verbose = args.verbose
|
||||
test_only = args.test_only
|
||||
|
||||
# if config file is not found, try to find it in the same directory as this script
|
||||
if not os.path.exists(config_file):
|
||||
config_file = os.path.join(os.path.dirname(__file__), config_file)
|
||||
with open(config_file) as f:
|
||||
config = json.load(f)
|
||||
|
||||
if len(boards) == 0:
|
||||
config_boards = [e for e in config['boards'] if e['name'] not in skip_boards]
|
||||
else:
|
||||
config_boards = [e for e in config['boards'] if e['name'] in boards]
|
||||
|
||||
err_count = 0
|
||||
with Pool(processes=os.cpu_count()) as pool:
|
||||
mret = pool.map(test_board, config_boards)
|
||||
err_count = sum(e[1] for e in mret)
|
||||
# generate skip list for next re-run if failed
|
||||
skip_fname = f'{config_file}.skip'
|
||||
if err_count > 0:
|
||||
skip_boards += [name for name, err in mret if err == 0]
|
||||
with open(skip_fname, 'w') as f:
|
||||
f.write(' '.join(f'-s {i}' for i in skip_boards))
|
||||
elif os.path.exists(skip_fname):
|
||||
os.remove(skip_fname)
|
||||
|
||||
duration = time.time() - duration
|
||||
print()
|
||||
print("-" * 30)
|
||||
print(f'Total failed: {err_count} in {duration:.1f}s')
|
||||
print("-" * 30)
|
||||
sys.exit(err_count)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
1290
managed_components/espressif__tinyusb/test/hil/pymtp.py
Normal file
1290
managed_components/espressif__tinyusb/test/hil/pymtp.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
fs
|
||||
pyfatfs
|
||||
269
managed_components/espressif__tinyusb/test/hil/tinyusb.json
Normal file
269
managed_components/espressif__tinyusb/test/hil/tinyusb.json
Normal file
@@ -0,0 +1,269 @@
|
||||
{
|
||||
"boards": [
|
||||
{
|
||||
"name": "espressif_p4_function_ev",
|
||||
"uid": "6055F9F98715",
|
||||
"build" : {
|
||||
"flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE"]
|
||||
},
|
||||
"tests": {
|
||||
"only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "host/device_info"],
|
||||
"dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002427"}]
|
||||
},
|
||||
"flasher": {
|
||||
"name": "esptool",
|
||||
"uid": "4ea4f48f6bc3ee11bbb9d00f9e1b1c54",
|
||||
"args": "-b 1500000"
|
||||
},
|
||||
"comment": "Use TS3USB30 mux to test both device and host"
|
||||
},
|
||||
{
|
||||
"name": "espressif_s3_devkitm",
|
||||
"uid": "84F703C084E4",
|
||||
"build" : {
|
||||
"flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE"]
|
||||
},
|
||||
"tests": {
|
||||
"only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "host/device_info"],
|
||||
"dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2005402"}]
|
||||
},
|
||||
"flasher": {
|
||||
"name": "esptool",
|
||||
"uid": "3ea619acd1cdeb11a0a0b806e93fd3f1",
|
||||
"args": "-b 1500000"
|
||||
},
|
||||
"comment": "Use TS3USB30 mux to test both device and host"
|
||||
},
|
||||
{
|
||||
"name": "feather_nrf52840_express",
|
||||
"uid": "1F0479CD0F764471",
|
||||
"tests": {
|
||||
"device": true, "host": false, "dual": false
|
||||
},
|
||||
"flasher": {
|
||||
"name": "jlink",
|
||||
"uid": "000682804350",
|
||||
"args": "-device nrf52840_xxaa"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "max32666fthr",
|
||||
"uid": "0C81464124010B20FF0A08CC2C",
|
||||
"tests": {
|
||||
"device": true, "host": false, "dual": false
|
||||
},
|
||||
"flasher": {
|
||||
"name": "openocd_adi",
|
||||
"uid": "E6614C311B597D32",
|
||||
"args": "-f interface/cmsis-dap.cfg -f target/max32665.cfg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "metro_m4_express",
|
||||
"uid": "9995AD485337433231202020FF100A34",
|
||||
"build" : {
|
||||
"args": ["MAX3421_HOST=1"]
|
||||
},
|
||||
"tests": {
|
||||
"device": true, "host": false, "dual": true,
|
||||
"dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002130"}]
|
||||
},
|
||||
"flasher": {
|
||||
"name": "jlink",
|
||||
"uid": "123456",
|
||||
"args": "-device ATSAMD51J19"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mimxrt1064_evk",
|
||||
"uid": "BAE96FB95AFA6DBB8F00005002001200",
|
||||
"tests": {
|
||||
"device": true, "host": true, "dual": true,
|
||||
"dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2023299"}]
|
||||
},
|
||||
"flasher": {
|
||||
"name": "jlink",
|
||||
"uid": "000725299165",
|
||||
"args": "-device MIMXRT1064xxx6A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "lpcxpresso11u37",
|
||||
"uid": "17121919",
|
||||
"tests": {
|
||||
"device": true, "host": false, "dual": false
|
||||
},
|
||||
"flasher": {
|
||||
"name": "jlink",
|
||||
"uid": "000724441579",
|
||||
"args": "-device LPC11U37/401"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ra4m1_ek",
|
||||
"uid": "152E163038303131393346E46F26574B",
|
||||
"tests": {
|
||||
"device": true, "host": false, "dual": false,
|
||||
"skip": ["device/cdc_msc", "device/cdc_msc_freertos"]
|
||||
},
|
||||
"comment": "MSC is slow to enumerated #2602",
|
||||
"flasher": {
|
||||
"name": "jlink",
|
||||
"uid": "000831174392",
|
||||
"args": "-device R7FA4M1AB"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "raspberry_pi_pico",
|
||||
"uid": "E6614C311B764A37",
|
||||
"build" : {
|
||||
"flags_on": ["CFG_TUH_RPI_PIO_USB"]
|
||||
},
|
||||
"tests": {
|
||||
"device": true, "host": true, "dual": true,
|
||||
"dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002470"}]
|
||||
},
|
||||
"flasher": {
|
||||
"name": "openocd",
|
||||
"uid": "E6614103E72C1D2F",
|
||||
"args": "-f interface/cmsis-dap.cfg -f target/rp2040.cfg -c \"adapter speed 5000\""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "raspberry_pi_pico_w",
|
||||
"uid": "E6614C311B764A37",
|
||||
"tests": {
|
||||
"device": false, "host": true, "dual": false,
|
||||
"dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2023934"}]
|
||||
},
|
||||
"flasher": {
|
||||
"name": "openocd",
|
||||
"uid": "E6633861A3819D38",
|
||||
"args": "-f interface/cmsis-dap.cfg -f target/rp2040.cfg -c \"adapter speed 5000\""
|
||||
},
|
||||
"comment": "Test native host"
|
||||
},
|
||||
{
|
||||
"name": "raspberry_pi_pico2",
|
||||
"uid": "560AE75E1C7152C9",
|
||||
"build" : {
|
||||
"flags_on": ["CFG_TUH_RPI_PIO_USB"]
|
||||
},
|
||||
"tests": {
|
||||
"device": true, "host": true, "dual": true,
|
||||
"dev_attached": [{"vid_pid": "1a86_55d4", "serial": "533D004242"}]
|
||||
},
|
||||
"flasher": {
|
||||
"name": "openocd",
|
||||
"uid": "E6633861A3978538",
|
||||
"args": "-f interface/cmsis-dap.cfg -f target/rp2350.cfg -c \"adapter speed 5000\""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "stm32f072disco",
|
||||
"uid": "3A001A001357364230353532",
|
||||
"flasher": {
|
||||
"name": "jlink",
|
||||
"uid": "779541626",
|
||||
"args": "-device stm32f072rb"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "stm32f723disco",
|
||||
"uid": "460029001951373031313335",
|
||||
"build" : {
|
||||
"flags_on": ["", "CFG_TUH_DWC2_DMA_ENABLE"]
|
||||
},
|
||||
"tests": {
|
||||
"device": true, "host": true, "dual": false,
|
||||
"dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2003414"}]
|
||||
},
|
||||
"flasher": {
|
||||
"name": "jlink",
|
||||
"uid": "000776606156",
|
||||
"args": "-device stm32f723ie"
|
||||
},
|
||||
"comment": "Device port0 FS (slave only), Host port1 HS with DMA"
|
||||
},
|
||||
{
|
||||
"name": "stm32h743nucleo",
|
||||
"uid": "110018000951383432343236",
|
||||
"build" : {
|
||||
"flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE"]
|
||||
},
|
||||
"tests": {
|
||||
"device": true, "host": false, "dual": false
|
||||
},
|
||||
"flasher": {
|
||||
"name": "openocd",
|
||||
"uid": "004C00343137510F39383538",
|
||||
"args": "-f interface/stlink.cfg -f target/stm32h7x.cfg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "stm32g0b1nucleo",
|
||||
"uid": "4D0038000450434E37343120",
|
||||
"tests": {
|
||||
"device": true, "host": false, "dual": false
|
||||
},
|
||||
"flasher": {
|
||||
"name": "openocd",
|
||||
"uid": "066FFF495087534867063844",
|
||||
"args": "-f interface/stlink.cfg -f target/stm32g0x.cfg"
|
||||
}
|
||||
}
|
||||
],
|
||||
"boards-skip": [
|
||||
{
|
||||
"name": "stm32f769disco",
|
||||
"uid": "21002F000F51363531383437",
|
||||
"build" : {
|
||||
"flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE"]
|
||||
},
|
||||
"tests": {
|
||||
"device": true, "host": false, "dual": false
|
||||
},
|
||||
"flasher": {
|
||||
"name": "jlink",
|
||||
"uid": "000778170924",
|
||||
"args": "-device stm32f769ni"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mimxrt1015_evk",
|
||||
"uid": "DC28F865D2111D228D00B0543A70463C",
|
||||
"tests": {
|
||||
"device": true, "host": false, "dual": false
|
||||
},
|
||||
"flasher": {
|
||||
"name": "jlink",
|
||||
"uid": "000726284213",
|
||||
"args": "-device MIMXRT1015DAF5A"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "nanoch32v203",
|
||||
"uid": "CDAB277B0FBC03E339E339E3",
|
||||
"tests": {
|
||||
"device": true, "host": false, "dual": false
|
||||
},
|
||||
"flasher": {
|
||||
"name": "openocd_wch",
|
||||
"uid": "EBCA8F0670AF",
|
||||
"args": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "stm32f407disco",
|
||||
"uid": "30001A000647313332353735",
|
||||
"tests": {
|
||||
"device": true, "host": false, "dual": false
|
||||
},
|
||||
"flasher": {
|
||||
"name": "jlink",
|
||||
"uid": "000773661813",
|
||||
"args": "-device stm32f407vg"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
ruby vendor/ceedling/bin/ceedling $*
|
||||
437
managed_components/espressif__tinyusb/test/unit-test/project.yml
Normal file
437
managed_components/espressif__tinyusb/test/unit-test/project.yml
Normal file
@@ -0,0 +1,437 @@
|
||||
# =========================================================================
|
||||
# Ceedling - Test-Centered Build System for C
|
||||
# ThrowTheSwitch.org
|
||||
# Copyright (c) 2010-25 Mike Karlesky, Mark VanderVoord, & Greg Williams
|
||||
# SPDX-License-Identifier: MIT
|
||||
# =========================================================================
|
||||
|
||||
---
|
||||
:project:
|
||||
# how to use ceedling. If you're not sure, leave this as `gem` and `?`
|
||||
:which_ceedling: gem
|
||||
:ceedling_version: 1.0.0
|
||||
:verbosity: 3
|
||||
|
||||
# optional features. If you don't need them, keep them turned off for performance
|
||||
:use_mocks: TRUE
|
||||
:use_test_preprocessor: :mocks # options are :none, :mocks, :tests, or :all
|
||||
:use_deep_dependencies: :all # options are :none, :mocks, :tests, or :all
|
||||
:use_backtrace: :simple # options are :none, :simple, or :gdb
|
||||
:use_decorators: :auto # decorate Ceedling's output text. options are :auto, :all, or :none
|
||||
|
||||
# tweak the way ceedling handles automatic tasks
|
||||
:build_root: _build
|
||||
:test_file_prefix: test_
|
||||
:default_tasks:
|
||||
- test:all
|
||||
|
||||
# performance options. If your tools start giving mysterious errors, consider
|
||||
# dropping this to 1 to force single-tasking
|
||||
:test_threads: 8
|
||||
:compile_threads: 8
|
||||
|
||||
# enable release build (more details in release_build section below)
|
||||
:release_build: FALSE
|
||||
|
||||
# Specify where to find mixins and any that should be enabled automatically
|
||||
:mixins:
|
||||
:enabled: []
|
||||
:load_paths: []
|
||||
|
||||
# further details to configure the way Ceedling handles test code
|
||||
:test_build:
|
||||
:use_assembly: FALSE
|
||||
|
||||
:test_runner:
|
||||
# Insert additional #include statements in a generated runner
|
||||
:includes:
|
||||
- osal.h
|
||||
|
||||
# further details to configure the way Ceedling handles release code
|
||||
:release_build:
|
||||
:output: MyApp.out
|
||||
:use_assembly: FALSE
|
||||
:artifacts: []
|
||||
|
||||
# Plugins are optional Ceedling features which can be enabled. Ceedling supports
|
||||
# a variety of plugins which may effect the way things are compiled, reported,
|
||||
# or may provide new command options. Refer to the readme in each plugin for
|
||||
# details on how to use it.
|
||||
:plugins:
|
||||
:load_paths: []
|
||||
:enabled:
|
||||
#- beep # beeps when finished, so you don't waste time waiting for ceedling
|
||||
- module_generator # handy for quickly creating source, header, and test templates
|
||||
#- gcov # test coverage using gcov. Requires gcc, gcov, and a coverage analyzer like gcovr
|
||||
#- bullseye # test coverage using bullseye. Requires bullseye for your platform
|
||||
#- command_hooks # write custom actions to be called at different points during the build process
|
||||
#- compile_commands_json_db # generate a compile_commands.json file
|
||||
#- dependencies # automatically fetch 3rd party libraries, etc.
|
||||
#- subprojects # managing builds and test for static libraries
|
||||
#- fake_function_framework # use FFF instead of CMock
|
||||
|
||||
# Report options (You'll want to choose one stdout option, but may choose multiple stored options if desired)
|
||||
#- report_build_warnings_log
|
||||
#- report_tests_gtestlike_stdout
|
||||
#- report_tests_ide_stdout
|
||||
#- report_tests_log_factory
|
||||
- report_tests_pretty_stdout
|
||||
#- report_tests_raw_output_log
|
||||
#- report_tests_teamcity_stdout
|
||||
|
||||
# Specify which reports you'd like from the log factory
|
||||
:report_tests_log_factory:
|
||||
:reports:
|
||||
- json
|
||||
- junit
|
||||
- cppunit
|
||||
- html
|
||||
|
||||
# override the default extensions for your system and toolchain
|
||||
:extension:
|
||||
#:header: .h
|
||||
#:source: .c
|
||||
#:assembly: .s
|
||||
#:dependencies: .d
|
||||
#:object: .o
|
||||
:executable: .out
|
||||
#:testpass: .pass
|
||||
#:testfail: .fail
|
||||
#:subprojects: .a
|
||||
|
||||
# This is where Ceedling should look for your source and test files.
|
||||
# see documentation for the many options for specifying this.
|
||||
:paths:
|
||||
:test:
|
||||
- +:test/**
|
||||
- -:test/support
|
||||
:source:
|
||||
- ../../src/**
|
||||
:include:
|
||||
- ../../src/**
|
||||
:support:
|
||||
- test/support
|
||||
:libraries: []
|
||||
|
||||
# You can even specify specific files to add or remove from your test
|
||||
# and release collections. Usually it's better to use paths and let
|
||||
# Ceedling do the work for you!
|
||||
:files:
|
||||
:test: []
|
||||
:source: []
|
||||
|
||||
# Compilation symbols to be injected into builds
|
||||
# See documentation for advanced options:
|
||||
# - Test name matchers for different symbols per test executable build
|
||||
# - Referencing symbols in multiple lists using advanced YAML
|
||||
# - Specifying symbols used during test preprocessing
|
||||
:defines:
|
||||
:test:
|
||||
- _UNITY_TEST_
|
||||
:release: []
|
||||
|
||||
# Enable to inject name of a test as a unique compilation symbol into its respective executable build.
|
||||
:use_test_definition: FALSE
|
||||
|
||||
# Configure additional command line flags provided to tools used in each build step
|
||||
# :flags:
|
||||
# :release:
|
||||
# :compile: # Add '-Wall' and '--02' to compilation of all files in release target
|
||||
# - -Wall
|
||||
# - --O2
|
||||
# :test:
|
||||
# :compile:
|
||||
# '(_|-)special': # Add '-pedantic' to compilation of all files in all test executables with '_special' or '-special' in their names
|
||||
# - -pedantic
|
||||
# '*': # Add '-foo' to compilation of all files in all test executables
|
||||
# - -foo
|
||||
|
||||
# Configuration Options specific to CMock. See CMock docs for details
|
||||
:cmock:
|
||||
# Core configuration
|
||||
:plugins: # What plugins should be used by CMock?
|
||||
- :ignore
|
||||
- :ignore_arg
|
||||
- :return_thru_ptr
|
||||
- :callback
|
||||
- :array
|
||||
:verbosity: 2 # the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose
|
||||
:when_no_prototypes: :warn # the options being :ignore, :warn, or :error
|
||||
|
||||
# File configuration
|
||||
:skeleton_path: '' # Subdirectory to store stubs when generated (default: '')
|
||||
:mock_prefix: 'mock_' # Prefix to append to filenames for mocks
|
||||
:mock_suffix: '' # Suffix to append to filenames for mocks
|
||||
|
||||
# Parser configuration
|
||||
:strippables: ['(?:__attribute__\s*\([ (]*.*?[ )]*\)+)']
|
||||
:attributes:
|
||||
- __ramfunc
|
||||
- __irq
|
||||
- __fiq
|
||||
- register
|
||||
- extern
|
||||
:c_calling_conventions:
|
||||
- __stdcall
|
||||
- __cdecl
|
||||
- __fastcall
|
||||
:treat_externs: :exclude # the options being :include or :exclud
|
||||
:treat_inlines: :exclude # the options being :include or :exclud
|
||||
|
||||
# Type handling configuration
|
||||
#:unity_helper_path: '' # specify a string of where to find a unity_helper.h file to discover custom type assertions
|
||||
:treat_as: # optionally add additional types to map custom types
|
||||
uint8: HEX8
|
||||
uint16: HEX16
|
||||
uint32: UINT32
|
||||
int8: INT8
|
||||
bool: UINT8
|
||||
#:treat_as_array: {} # hint to cmock that these types are pointers to something
|
||||
#:treat_as_void: [] # hint to cmock that these types are actually aliases of void
|
||||
:memcmp_if_unknown: true # allow cmock to use the memory comparison assertions for unknown types
|
||||
:when_ptr: :compare_data # hint to cmock how to handle pointers in general, the options being :compare_ptr, :compare_data, or :smart
|
||||
|
||||
# Mock generation configuration
|
||||
:weak: '' # Symbol to use to declare weak functions
|
||||
:enforce_strict_ordering: true # Do we want cmock to enforce ordering of all function calls?
|
||||
:fail_on_unexpected_calls: true # Do we want cmock to fail when it encounters a function call that wasn't expected?
|
||||
:callback_include_count: true # Do we want cmock to include the number of calls to this callback, when using callbacks?
|
||||
:callback_after_arg_check: false # Do we want cmock to enforce an argument check first when using a callback?
|
||||
#:includes: [] # You can add additional includes here, or specify the location with the options below
|
||||
#:includes_h_pre_orig_header: []
|
||||
#:includes_h_post_orig_header: []
|
||||
#:includes_c_pre_header: []
|
||||
#:includes_c_post_header: []
|
||||
#:array_size_type: [] # Specify a type or types that should be used for array lengths
|
||||
#:array_size_name: 'size|len' # Specify a name or names that CMock might automatically recognize as the length of an array
|
||||
:exclude_setjmp_h: false # Don't use setjmp when running CMock. Note that this might result in late reporting or out-of-order failures.
|
||||
|
||||
# Configuration options specific to Unity.
|
||||
:unity:
|
||||
:defines:
|
||||
- UNITY_EXCLUDE_FLOAT
|
||||
|
||||
# You can optionally have ceedling create environment variables for you before
|
||||
# performing the rest of its tasks.
|
||||
:environment: []
|
||||
# :environment:
|
||||
# # List enforces order allowing later to reference earlier with inline Ruby substitution
|
||||
# - :var1: value
|
||||
# - :var2: another value
|
||||
# - :path: # Special PATH handling with platform-specific path separators
|
||||
# - #{ENV['PATH']} # Environment variables can use inline Ruby substitution
|
||||
# - /another/path/to/include
|
||||
|
||||
# LIBRARIES
|
||||
# These libraries are automatically injected into the build process. Those specified as
|
||||
# common will be used in all types of builds. Otherwise, libraries can be injected in just
|
||||
# tests or releases. These options are MERGED with the options in supplemental yaml files.
|
||||
:libraries:
|
||||
:placement: :end
|
||||
:flag: "-l${1}"
|
||||
:path_flag: "-L ${1}"
|
||||
:system: [] # for example, you might list 'm' to grab the math library
|
||||
:test: []
|
||||
:release: []
|
||||
|
||||
################################################################
|
||||
# PLUGIN CONFIGURATION
|
||||
################################################################
|
||||
|
||||
# Add -gcov to the plugins list to make sure of the gcov plugin
|
||||
# You will need to have gcov and gcovr both installed to make it work.
|
||||
# For more information on these options, see docs in plugins/gcov
|
||||
:gcov:
|
||||
:summaries: TRUE # Enable simple coverage summaries to console after tests
|
||||
:report_task: FALSE # Disabled dedicated report generation task (this enables automatic report generation)
|
||||
:utilities:
|
||||
- gcovr # Use gcovr to create the specified reports (default).
|
||||
#- ReportGenerator # Use ReportGenerator to create the specified reports.
|
||||
:reports: # Specify one or more reports to generate.
|
||||
# Make an HTML summary report.
|
||||
- HtmlBasic
|
||||
# - HtmlDetailed
|
||||
# - Text
|
||||
# - Cobertura
|
||||
# - SonarQube
|
||||
# - JSON
|
||||
# - HtmlInline
|
||||
# - HtmlInlineAzure
|
||||
# - HtmlInlineAzureDark
|
||||
# - HtmlChart
|
||||
# - MHtml
|
||||
# - Badges
|
||||
# - CsvSummary
|
||||
# - Latex
|
||||
# - LatexSummary
|
||||
# - PngChart
|
||||
# - TeamCitySummary
|
||||
# - lcov
|
||||
# - Xml
|
||||
# - XmlSummary
|
||||
:gcovr:
|
||||
# :html_artifact_filename: TestCoverageReport.html
|
||||
# :html_title: Test Coverage Report
|
||||
:html_medium_threshold: 75
|
||||
:html_high_threshold: 90
|
||||
# :html_absolute_paths: TRUE
|
||||
# :html_encoding: UTF-8
|
||||
|
||||
# :module_generator:
|
||||
# :project_root: ./
|
||||
# :source_root: source/
|
||||
# :inc_root: includes/
|
||||
# :test_root: tests/
|
||||
# :naming: :snake #options: :bumpy, :camel, :caps, or :snake
|
||||
# :includes:
|
||||
# :tst: []
|
||||
# :src: []
|
||||
# :boilerplates:
|
||||
# :src: ""
|
||||
# :inc: ""
|
||||
# :tst: ""
|
||||
|
||||
# :dependencies:
|
||||
# :libraries:
|
||||
# - :name: WolfSSL
|
||||
# :source_path: third_party/wolfssl/source
|
||||
# :build_path: third_party/wolfssl/build
|
||||
# :artifact_path: third_party/wolfssl/install
|
||||
# :fetch:
|
||||
# :method: :zip
|
||||
# :source: \\shared_drive\third_party_libs\wolfssl\wolfssl-4.2.0.zip
|
||||
# :environment:
|
||||
# - CFLAGS+=-DWOLFSSL_DTLS_ALLOW_FUTURE
|
||||
# :build:
|
||||
# - "autoreconf -i"
|
||||
# - "./configure --enable-tls13 --enable-singlethreaded"
|
||||
# - make
|
||||
# - make install
|
||||
# :artifacts:
|
||||
# :static_libraries:
|
||||
# - lib/wolfssl.a
|
||||
# :dynamic_libraries:
|
||||
# - lib/wolfssl.so
|
||||
# :includes:
|
||||
# - include/**
|
||||
|
||||
# :subprojects:
|
||||
# :paths:
|
||||
# - :name: libprojectA
|
||||
# :source:
|
||||
# - ./subprojectA/source
|
||||
# :include:
|
||||
# - ./subprojectA/include
|
||||
# :build_root: ./subprojectA/build
|
||||
# :defines: []
|
||||
|
||||
# :command_hooks:
|
||||
# :pre_mock_preprocess:
|
||||
# :post_mock_preprocess:
|
||||
# :pre_test_preprocess:
|
||||
# :post_test_preprocess:
|
||||
# :pre_mock_generate:
|
||||
# :post_mock_generate:
|
||||
# :pre_runner_generate:
|
||||
# :post_runner_generate:
|
||||
# :pre_compile_execute:
|
||||
# :post_compile_execute:
|
||||
# :pre_link_execute:
|
||||
# :post_link_execute:
|
||||
# :pre_test_fixture_execute:
|
||||
# :post_test_fixture_execute:
|
||||
# :pre_test:
|
||||
# :post_test:
|
||||
# :pre_release:
|
||||
# :post_release:
|
||||
# :pre_build:
|
||||
# :post_build:
|
||||
# :post_error:
|
||||
|
||||
################################################################
|
||||
# TOOLCHAIN CONFIGURATION
|
||||
################################################################
|
||||
|
||||
#:tools:
|
||||
# Ceedling defaults to using gcc for compiling, linking, etc.
|
||||
# As [:tools] is blank, gcc will be used (so long as it's in your system path)
|
||||
# See documentation to configure a given toolchain for use
|
||||
#:tools:
|
||||
# :test_compiler:
|
||||
# :executable: gcc
|
||||
# :name: 'gcc compiler'
|
||||
# :arguments:
|
||||
# - -I"$": COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE #expands to -I search paths
|
||||
# - -I"$": COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR #expands to -I search paths
|
||||
# - -D$: COLLECTION_DEFINES_TEST_AND_VENDOR #expands to all -D defined symbols
|
||||
# #- -fsanitize=address
|
||||
# - -c ${1} #source code input file (Ruby method call param list sub)
|
||||
# - -o ${2} #object file output (Ruby method call param list sub)
|
||||
# :test_linker:
|
||||
# :executable: gcc
|
||||
# :name: 'gcc linker'
|
||||
# :arguments:
|
||||
# #- -fsanitize=address
|
||||
# - ${1} #list of object files to link (Ruby method call param list sub)
|
||||
# - -o ${2} #executable file output (Ruby method call param list sub)
|
||||
# :test_compiler:
|
||||
# :executable:
|
||||
# :arguments: []
|
||||
# :name:
|
||||
# :optional: FALSE
|
||||
# :test_linker:
|
||||
# :executable:
|
||||
# :arguments: []
|
||||
# :name:
|
||||
# :optional: FALSE
|
||||
# :test_assembler:
|
||||
# :executable:
|
||||
# :arguments: []
|
||||
# :name:
|
||||
# :optional: FALSE
|
||||
# :test_fixture:
|
||||
# :executable:
|
||||
# :arguments: []
|
||||
# :name:
|
||||
# :optional: FALSE
|
||||
# :test_includes_preprocessor:
|
||||
# :executable:
|
||||
# :arguments: []
|
||||
# :name:
|
||||
# :optional: FALSE
|
||||
# :test_file_preprocessor:
|
||||
# :executable:
|
||||
# :arguments: []
|
||||
# :name:
|
||||
# :optional: FALSE
|
||||
# :test_file_preprocessor_directives:
|
||||
# :executable:
|
||||
# :arguments: []
|
||||
# :name:
|
||||
# :optional: FALSE
|
||||
# :test_dependencies_generator:
|
||||
# :executable:
|
||||
# :arguments: []
|
||||
# :name:
|
||||
# :optional: FALSE
|
||||
# :release_compiler:
|
||||
# :executable:
|
||||
# :arguments: []
|
||||
# :name:
|
||||
# :optional: FALSE
|
||||
# :release_linker:
|
||||
# :executable:
|
||||
# :arguments: []
|
||||
# :name:
|
||||
# :optional: FALSE
|
||||
# :release_assembler:
|
||||
# :executable:
|
||||
# :arguments: []
|
||||
# :name:
|
||||
# :optional: FALSE
|
||||
# :release_dependencies_generator:
|
||||
# :executable:
|
||||
# :arguments: []
|
||||
# :name:
|
||||
# :optional: FALSE
|
||||
...
|
||||
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019, hathach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
|
||||
#include "unity.h"
|
||||
|
||||
// Files to test
|
||||
#include "osal/osal.h"
|
||||
#include "tusb_fifo.h"
|
||||
#include "tusb.h"
|
||||
#include "usbd.h"
|
||||
TEST_SOURCE_FILE("usbd_control.c")
|
||||
TEST_SOURCE_FILE("msc_device.c")
|
||||
|
||||
// Mock File
|
||||
#include "mock_dcd.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
uint32_t tusb_time_millis_api(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
EDPT_CTRL_OUT = 0x00,
|
||||
EDPT_CTRL_IN = 0x80,
|
||||
|
||||
EDPT_MSC_OUT = 0x01,
|
||||
EDPT_MSC_IN = 0x81,
|
||||
};
|
||||
|
||||
uint8_t const rhport = 0;
|
||||
|
||||
enum
|
||||
{
|
||||
ITF_NUM_MSC,
|
||||
ITF_NUM_TOTAL
|
||||
};
|
||||
|
||||
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN)
|
||||
|
||||
uint8_t const data_desc_configuration[] =
|
||||
{
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
|
||||
// Interface number, string index, EP Out & EP In address, EP size
|
||||
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EDPT_MSC_OUT, EDPT_MSC_IN, TUD_OPT_HIGH_SPEED ? 512 : 64),
|
||||
};
|
||||
|
||||
tusb_control_request_t const request_set_configuration =
|
||||
{
|
||||
.bmRequestType = 0x00,
|
||||
.bRequest = TUSB_REQ_SET_CONFIGURATION,
|
||||
.wValue = 1,
|
||||
.wIndex = 0,
|
||||
.wLength = 0
|
||||
};
|
||||
|
||||
uint8_t const* desc_configuration;
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount
|
||||
DISK_BLOCK_SIZE = 512
|
||||
};
|
||||
|
||||
uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE];
|
||||
|
||||
// Invoked when received SCSI_CMD_INQUIRY, v2 with full inquiry response
|
||||
// Some inquiry_resp's fields are already filled with default values, application can update them
|
||||
// Return length of inquiry response, typically sizeof(scsi_inquiry_resp_t) (36 bytes), can be longer if included vendor data.
|
||||
uint32_t tud_msc_inquiry2_cb(uint8_t lun, scsi_inquiry_resp_t* inquiry_resp, uint32_t bufsize) {
|
||||
(void) lun;
|
||||
(void) bufsize;
|
||||
const char vid[] = "TinyUSB";
|
||||
const char pid[] = "Mass Storage";
|
||||
const char rev[] = "1.0";
|
||||
|
||||
memcpy(inquiry_resp->vendor_id, vid, strlen(vid));
|
||||
memcpy(inquiry_resp->product_id, pid, strlen(pid));
|
||||
memcpy(inquiry_resp->product_rev, rev, strlen(rev));
|
||||
|
||||
return sizeof(scsi_inquiry_resp_t); // 36 bytes
|
||||
}
|
||||
|
||||
// Invoked when received Test Unit Ready command.
|
||||
// return true allowing host to read/write this LUN e.g SD card inserted
|
||||
bool tud_msc_test_unit_ready_cb(uint8_t lun)
|
||||
{
|
||||
(void) lun;
|
||||
|
||||
return true; // RAM disk is always ready
|
||||
}
|
||||
|
||||
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
|
||||
// Application update block count and block size
|
||||
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
|
||||
{
|
||||
(void) lun;
|
||||
|
||||
*block_count = DISK_BLOCK_NUM;
|
||||
*block_size = DISK_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
// Invoked when received Start Stop Unit command
|
||||
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
|
||||
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
|
||||
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
|
||||
{
|
||||
(void) lun;
|
||||
(void) power_condition;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
|
||||
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
(void) lun;
|
||||
|
||||
uint8_t const* addr = msc_disk[lba] + offset;
|
||||
memcpy(buffer, addr, bufsize);
|
||||
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and return number of written bytes
|
||||
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
(void) lun;
|
||||
|
||||
uint8_t* addr = msc_disk[lba] + offset;
|
||||
memcpy(addr, buffer, bufsize);
|
||||
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
// Callback invoked when received an SCSI command not in built-in list below
|
||||
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
|
||||
// - READ10 and WRITE10 has their own callbacks
|
||||
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
|
||||
{
|
||||
// read10 & write10 has their own callback and MUST not be handled here
|
||||
|
||||
void const* response = NULL;
|
||||
uint16_t resplen = 0;
|
||||
|
||||
return resplen;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
//
|
||||
//--------------------------------------------------------------------+
|
||||
uint8_t const * tud_descriptor_device_cb(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
|
||||
{
|
||||
return desc_configuration;
|
||||
}
|
||||
|
||||
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
|
||||
{
|
||||
(void) langid;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
dcd_int_disable_Ignore();
|
||||
dcd_int_enable_Ignore();
|
||||
|
||||
if ( !tud_inited() ) {
|
||||
tusb_rhport_init_t dev_init = {
|
||||
.role = TUSB_ROLE_DEVICE,
|
||||
.speed = TUSB_SPEED_AUTO
|
||||
};
|
||||
|
||||
dcd_init_ExpectAndReturn(0, &dev_init, true);
|
||||
tusb_init(0, &dev_init);
|
||||
}
|
||||
|
||||
dcd_event_bus_reset(rhport, TUSB_SPEED_HIGH, false);
|
||||
tud_task();
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
//
|
||||
//--------------------------------------------------------------------+
|
||||
void test_msc(void)
|
||||
{
|
||||
// Read 1 LBA = 0, Block count = 1
|
||||
msc_cbw_t cbw_read10 =
|
||||
{
|
||||
.signature = MSC_CBW_SIGNATURE,
|
||||
.tag = 0xCAFECAFE,
|
||||
.total_bytes = 512,
|
||||
.lun = 0,
|
||||
.dir = TUSB_DIR_IN_MASK,
|
||||
.cmd_len = sizeof(scsi_read10_t)
|
||||
};
|
||||
|
||||
scsi_read10_t cmd_read10 =
|
||||
{
|
||||
.cmd_code = SCSI_CMD_READ_10,
|
||||
.lba = tu_htonl(0),
|
||||
.block_count = tu_htons(1)
|
||||
};
|
||||
|
||||
memcpy(cbw_read10.command, &cmd_read10, cbw_read10.cmd_len);
|
||||
|
||||
desc_configuration = data_desc_configuration;
|
||||
uint8_t const* desc_ep = tu_desc_next(tu_desc_next(desc_configuration));
|
||||
|
||||
dcd_event_setup_received(rhport, (uint8_t*) &request_set_configuration, false);
|
||||
|
||||
// open endpoints
|
||||
dcd_edpt_open_ExpectAndReturn(rhport, (tusb_desc_endpoint_t const *) desc_ep, true);
|
||||
dcd_edpt_open_ExpectAndReturn(rhport, (tusb_desc_endpoint_t const *) tu_desc_next(desc_ep), true);
|
||||
|
||||
// Prepare SCSI command
|
||||
dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_MSC_OUT, NULL, sizeof(msc_cbw_t), true);
|
||||
dcd_edpt_xfer_IgnoreArg_buffer();
|
||||
dcd_edpt_xfer_ReturnMemThruPtr_buffer( (uint8_t*) &cbw_read10, sizeof(msc_cbw_t));
|
||||
|
||||
// command received
|
||||
dcd_event_xfer_complete(rhport, EDPT_MSC_OUT, sizeof(msc_cbw_t), 0, true);
|
||||
|
||||
// control status
|
||||
dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_IN, NULL, 0, true);
|
||||
|
||||
// SCSI Data transfer
|
||||
dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_MSC_IN, NULL, 512, true);
|
||||
dcd_edpt_xfer_IgnoreArg_buffer();
|
||||
dcd_event_xfer_complete(rhport, EDPT_MSC_IN, 512, 0, true); // complete
|
||||
|
||||
// SCSI Status
|
||||
dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_MSC_IN, NULL, 13, true);
|
||||
dcd_edpt_xfer_IgnoreArg_buffer();
|
||||
dcd_event_xfer_complete(rhport, EDPT_MSC_IN, 13, 0, true);
|
||||
|
||||
// Prepare for next command
|
||||
dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_MSC_OUT, NULL, sizeof(msc_cbw_t), true);
|
||||
dcd_edpt_xfer_IgnoreArg_buffer();
|
||||
|
||||
tud_task();
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019, Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
|
||||
// Files to test
|
||||
#include "osal/osal.h"
|
||||
#include "tusb_fifo.h"
|
||||
#include "tusb.h"
|
||||
#include "usbd.h"
|
||||
TEST_SOURCE_FILE("usbd_control.c")
|
||||
|
||||
// Mock File
|
||||
#include "mock_dcd.h"
|
||||
#include "mock_msc_device.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
uint32_t tusb_time_millis_api(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
EDPT_CTRL_OUT = 0x00,
|
||||
EDPT_CTRL_IN = 0x80
|
||||
};
|
||||
|
||||
uint8_t const rhport = 0;
|
||||
|
||||
tusb_desc_device_t const data_desc_device =
|
||||
{
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = 0x0200,
|
||||
|
||||
// Use Interface Association Descriptor (IAD) for CDC
|
||||
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
|
||||
.bDeviceClass = TUSB_CLASS_MISC,
|
||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
|
||||
.idVendor = 0xCafe,
|
||||
.idProduct = 0xCafe,
|
||||
.bcdDevice = 0x0100,
|
||||
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
uint8_t const data_desc_configuration[] =
|
||||
{
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUD_CONFIG_DESC_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
};
|
||||
|
||||
tusb_control_request_t const req_get_desc_device =
|
||||
{
|
||||
.bmRequestType = 0x80,
|
||||
.bRequest = TUSB_REQ_GET_DESCRIPTOR,
|
||||
.wValue = (TUSB_DESC_DEVICE << 8),
|
||||
.wIndex = 0x0000,
|
||||
.wLength = 64
|
||||
};
|
||||
|
||||
tusb_control_request_t const req_get_desc_configuration =
|
||||
{
|
||||
.bmRequestType = 0x80,
|
||||
.bRequest = TUSB_REQ_GET_DESCRIPTOR,
|
||||
.wValue = (TUSB_DESC_CONFIGURATION << 8),
|
||||
.wIndex = 0x0000,
|
||||
.wLength = 256
|
||||
};
|
||||
|
||||
uint8_t const* desc_device;
|
||||
uint8_t const* desc_configuration;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
//
|
||||
//--------------------------------------------------------------------+
|
||||
uint8_t const * tud_descriptor_device_cb(void) {
|
||||
return desc_device;
|
||||
}
|
||||
|
||||
uint8_t const * tud_descriptor_configuration_cb(uint8_t index) {
|
||||
return desc_configuration;
|
||||
}
|
||||
|
||||
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
||||
(void) langid;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void setUp(void) {
|
||||
dcd_int_disable_Ignore();
|
||||
dcd_int_enable_Ignore();
|
||||
|
||||
if ( !tud_inited() ) {
|
||||
tusb_rhport_init_t dev_init = {
|
||||
.role = TUSB_ROLE_DEVICE,
|
||||
.speed = TUSB_SPEED_AUTO
|
||||
};
|
||||
|
||||
mscd_init_Expect();
|
||||
dcd_init_ExpectAndReturn(0, &dev_init, true);
|
||||
|
||||
tusb_init(0, &dev_init);
|
||||
}
|
||||
}
|
||||
|
||||
void tearDown(void) {
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Get Descriptor
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//------------- Device -------------//
|
||||
void test_usbd_get_device_descriptor(void)
|
||||
{
|
||||
desc_device = (uint8_t const *) &data_desc_device;
|
||||
dcd_event_setup_received(rhport, (uint8_t*) &req_get_desc_device, false);
|
||||
|
||||
// data
|
||||
dcd_edpt_xfer_ExpectWithArrayAndReturn(rhport, 0x80, (uint8_t*)&data_desc_device, sizeof(tusb_desc_device_t), sizeof(tusb_desc_device_t), true);
|
||||
dcd_event_xfer_complete(rhport, EDPT_CTRL_IN, sizeof(tusb_desc_device_t), 0, false);
|
||||
|
||||
// status
|
||||
dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_OUT, NULL, 0, true);
|
||||
dcd_event_xfer_complete(rhport, EDPT_CTRL_OUT, 0, 0, false);
|
||||
dcd_edpt0_status_complete_ExpectWithArray(rhport, &req_get_desc_device, 1);
|
||||
|
||||
tud_task();
|
||||
}
|
||||
|
||||
void test_usbd_get_device_descriptor_null(void)
|
||||
{
|
||||
desc_device = NULL;
|
||||
|
||||
dcd_event_setup_received(rhport, (uint8_t*) &req_get_desc_device, false);
|
||||
|
||||
dcd_edpt_stall_Expect(rhport, EDPT_CTRL_OUT);
|
||||
dcd_edpt_stall_Expect(rhport, EDPT_CTRL_IN);
|
||||
|
||||
tud_task();
|
||||
}
|
||||
|
||||
//------------- Configuration -------------//
|
||||
|
||||
void test_usbd_get_configuration_descriptor(void)
|
||||
{
|
||||
desc_configuration = data_desc_configuration;
|
||||
uint16_t total_len = ((tusb_desc_configuration_t const*) data_desc_configuration)->wTotalLength;
|
||||
|
||||
dcd_event_setup_received(rhport, (uint8_t*) &req_get_desc_configuration, false);
|
||||
|
||||
// data
|
||||
dcd_edpt_xfer_ExpectWithArrayAndReturn(rhport, 0x80, (uint8_t*) data_desc_configuration, total_len, total_len, true);
|
||||
dcd_event_xfer_complete(rhport, EDPT_CTRL_IN, total_len, 0, false);
|
||||
|
||||
// status
|
||||
dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_OUT, NULL, 0, true);
|
||||
dcd_event_xfer_complete(rhport, EDPT_CTRL_OUT, 0, 0, false);
|
||||
dcd_edpt0_status_complete_ExpectWithArray(rhport, &req_get_desc_configuration, 1);
|
||||
|
||||
tud_task();
|
||||
}
|
||||
|
||||
void test_usbd_get_configuration_descriptor_null(void)
|
||||
{
|
||||
desc_configuration = NULL;
|
||||
dcd_event_setup_received(rhport, (uint8_t*) &req_get_desc_configuration, false);
|
||||
|
||||
dcd_edpt_stall_Expect(rhport, EDPT_CTRL_OUT);
|
||||
dcd_edpt_stall_Expect(rhport, EDPT_CTRL_IN);
|
||||
|
||||
tud_task();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Control ZLP
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void test_usbd_control_in_zlp(void)
|
||||
{
|
||||
// 128 byte total len, with EP0 size = 64, and request length = 256
|
||||
// ZLP must be return
|
||||
uint8_t zlp_desc_configuration[CFG_TUD_ENDPOINT0_SIZE*2] =
|
||||
{
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, 0, 0, CFG_TUD_ENDPOINT0_SIZE*2, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||
};
|
||||
|
||||
desc_configuration = zlp_desc_configuration;
|
||||
|
||||
// request, then 1st, 2nd xact + ZLP + status
|
||||
dcd_event_setup_received(rhport, (uint8_t*) &req_get_desc_configuration, false);
|
||||
|
||||
// 1st transaction
|
||||
dcd_edpt_xfer_ExpectWithArrayAndReturn(rhport, EDPT_CTRL_IN,
|
||||
zlp_desc_configuration, CFG_TUD_ENDPOINT0_SIZE, CFG_TUD_ENDPOINT0_SIZE, true);
|
||||
dcd_event_xfer_complete(rhport, EDPT_CTRL_IN, CFG_TUD_ENDPOINT0_SIZE, 0, false);
|
||||
|
||||
// 2nd transaction
|
||||
dcd_edpt_xfer_ExpectWithArrayAndReturn(rhport, EDPT_CTRL_IN,
|
||||
zlp_desc_configuration + CFG_TUD_ENDPOINT0_SIZE, CFG_TUD_ENDPOINT0_SIZE, CFG_TUD_ENDPOINT0_SIZE, true);
|
||||
dcd_event_xfer_complete(rhport, EDPT_CTRL_IN, CFG_TUD_ENDPOINT0_SIZE, 0, false);
|
||||
|
||||
// Expect Zero length Packet
|
||||
dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_IN, NULL, 0, true);
|
||||
dcd_event_xfer_complete(rhport, EDPT_CTRL_IN, 0, 0, false);
|
||||
|
||||
// Status
|
||||
dcd_edpt_xfer_ExpectAndReturn(rhport, EDPT_CTRL_OUT, NULL, 0, true);
|
||||
dcd_event_xfer_complete(rhport, EDPT_CTRL_OUT, 0, 0, false);
|
||||
dcd_edpt0_status_complete_ExpectWithArray(rhport, &req_get_desc_configuration, 1);
|
||||
|
||||
tud_task();
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_CONFIG_H_
|
||||
#define _TUSB_CONFIG_H_
|
||||
|
||||
// testing framework
|
||||
#include "unity.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// COMMON CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// defined by compiler flags for flexibility
|
||||
#ifndef CFG_TUSB_MCU
|
||||
//#error CFG_TUSB_MCU must be defined
|
||||
#define CFG_TUSB_MCU OPT_MCU_NRF5X
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_RHPORT0_MODE
|
||||
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED)
|
||||
#endif
|
||||
|
||||
#define CFG_TUSB_OS OPT_OS_NONE
|
||||
|
||||
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
|
||||
#ifndef CFG_TUSB_DEBUG
|
||||
#define CFG_TUSB_DEBUG 1
|
||||
#endif
|
||||
|
||||
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||
* into those specific section.
|
||||
* e.g
|
||||
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
|
||||
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
|
||||
*/
|
||||
#ifndef CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUSB_MEM_SECTION
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_MEM_ALIGN
|
||||
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DEVICE CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#define CFG_TUD_TASK_QUEUE_SZ 100
|
||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||
|
||||
//------------- CLASS -------------//
|
||||
//#define CFG_TUD_CDC 0
|
||||
#define CFG_TUD_MSC 1
|
||||
//#define CFG_TUD_HID 0
|
||||
//#define CFG_TUD_MIDI 0
|
||||
//#define CFG_TUD_VENDOR 0
|
||||
|
||||
//------------- CDC -------------//
|
||||
|
||||
// FIFO size of CDC TX and RX
|
||||
#define CFG_TUD_CDC_RX_BUFSIZE 512
|
||||
#define CFG_TUD_CDC_TX_BUFSIZE 512
|
||||
|
||||
//------------- MSC -------------//
|
||||
|
||||
// Buffer size of Device Mass storage
|
||||
#define CFG_TUD_MSC_BUFSIZE 512
|
||||
|
||||
//------------- HID -------------//
|
||||
|
||||
// Should be sufficient to hold ID (if any) + Data
|
||||
#define CFG_TUD_HID_EP_BUFSIZE 64
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CONFIG_H_ */
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2023, Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
|
||||
#include "tusb_common.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
|
||||
//------------- IMPLEMENTATION -------------//
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
}
|
||||
|
||||
void test_TU_ARGS_NUM(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL( 0, TU_ARGS_NUM());
|
||||
TEST_ASSERT_EQUAL( 1, TU_ARGS_NUM(a1));
|
||||
TEST_ASSERT_EQUAL( 2, TU_ARGS_NUM(a1, a2));
|
||||
TEST_ASSERT_EQUAL( 3, TU_ARGS_NUM(a1, a2, a3));
|
||||
TEST_ASSERT_EQUAL( 4, TU_ARGS_NUM(a1, a2, a3, a4));
|
||||
TEST_ASSERT_EQUAL( 5, TU_ARGS_NUM(a1, a2, a3, a4, a5));
|
||||
TEST_ASSERT_EQUAL( 6, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6));
|
||||
TEST_ASSERT_EQUAL( 7, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7));
|
||||
TEST_ASSERT_EQUAL( 8, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8));
|
||||
TEST_ASSERT_EQUAL( 9, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9));
|
||||
TEST_ASSERT_EQUAL(10, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10));
|
||||
TEST_ASSERT_EQUAL(11, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11));
|
||||
TEST_ASSERT_EQUAL(12, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12));
|
||||
TEST_ASSERT_EQUAL(13, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13));
|
||||
TEST_ASSERT_EQUAL(14, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14));
|
||||
TEST_ASSERT_EQUAL(15, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15));
|
||||
TEST_ASSERT_EQUAL(16, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16));
|
||||
TEST_ASSERT_EQUAL(17, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17));
|
||||
TEST_ASSERT_EQUAL(18, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18));
|
||||
TEST_ASSERT_EQUAL(19, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19));
|
||||
TEST_ASSERT_EQUAL(20, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20));
|
||||
TEST_ASSERT_EQUAL(21, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21));
|
||||
TEST_ASSERT_EQUAL(22, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22));
|
||||
TEST_ASSERT_EQUAL(23, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23));
|
||||
TEST_ASSERT_EQUAL(24, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24));
|
||||
TEST_ASSERT_EQUAL(25, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25));
|
||||
TEST_ASSERT_EQUAL(26, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26));
|
||||
TEST_ASSERT_EQUAL(27, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27));
|
||||
TEST_ASSERT_EQUAL(28, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28));
|
||||
TEST_ASSERT_EQUAL(29, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29));
|
||||
TEST_ASSERT_EQUAL(30, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30));
|
||||
TEST_ASSERT_EQUAL(31, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31));
|
||||
TEST_ASSERT_EQUAL(32, TU_ARGS_NUM(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32));
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
|
||||
#include "osal/osal.h"
|
||||
#include "tusb_fifo.h"
|
||||
|
||||
#define FIFO_SIZE 64
|
||||
uint8_t tu_ff_buf[FIFO_SIZE * sizeof(uint8_t)];
|
||||
tu_fifo_t tu_ff = TU_FIFO_INIT(tu_ff_buf, FIFO_SIZE, uint8_t, false);
|
||||
|
||||
tu_fifo_t* ff = &tu_ff;
|
||||
tu_fifo_buffer_info_t info;
|
||||
|
||||
uint8_t test_data[4096];
|
||||
uint8_t rd_buf[FIFO_SIZE];
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
tu_fifo_clear(ff);
|
||||
memset(&info, 0, sizeof(tu_fifo_buffer_info_t));
|
||||
|
||||
for(int i=0; i<sizeof(test_data); i++) test_data[i] = i;
|
||||
memset(rd_buf, 0, sizeof(rd_buf));
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Tests
|
||||
//--------------------------------------------------------------------+
|
||||
void test_normal(void)
|
||||
{
|
||||
for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(ff, &i);
|
||||
|
||||
for(uint8_t i=0; i < FIFO_SIZE; i++)
|
||||
{
|
||||
uint8_t c;
|
||||
tu_fifo_read(ff, &c);
|
||||
TEST_ASSERT_EQUAL(i, c);
|
||||
}
|
||||
}
|
||||
|
||||
void test_item_size(void)
|
||||
{
|
||||
uint8_t ff4_buf[FIFO_SIZE * sizeof(uint32_t)];
|
||||
tu_fifo_t ff4 = TU_FIFO_INIT(ff4_buf, FIFO_SIZE, uint32_t, false);
|
||||
|
||||
uint32_t data4[2*FIFO_SIZE];
|
||||
for(uint32_t i=0; i<sizeof(data4)/4; i++) data4[i] = i;
|
||||
|
||||
// fill up fifo
|
||||
tu_fifo_write_n(&ff4, data4, FIFO_SIZE);
|
||||
|
||||
uint32_t rd_buf4[FIFO_SIZE];
|
||||
uint16_t rd_count;
|
||||
|
||||
// read 0 -> 4
|
||||
rd_count = tu_fifo_read_n(&ff4, rd_buf4, 5);
|
||||
TEST_ASSERT_EQUAL( 5, rd_count );
|
||||
TEST_ASSERT_EQUAL_UINT32_ARRAY( data4, rd_buf4, rd_count ); // 0 -> 4
|
||||
|
||||
tu_fifo_write_n(&ff4, data4+FIFO_SIZE, 5);
|
||||
|
||||
// read all 5 -> 68
|
||||
rd_count = tu_fifo_read_n(&ff4, rd_buf4, FIFO_SIZE);
|
||||
TEST_ASSERT_EQUAL( FIFO_SIZE, rd_count );
|
||||
TEST_ASSERT_EQUAL_UINT32_ARRAY( data4+5, rd_buf4, rd_count ); // 5 -> 68
|
||||
}
|
||||
|
||||
void test_read_n(void)
|
||||
{
|
||||
uint16_t rd_count;
|
||||
|
||||
// fill up fifo
|
||||
for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(ff, test_data+i);
|
||||
|
||||
// case 1: Read index + count < depth
|
||||
// read 0 -> 4
|
||||
rd_count = tu_fifo_read_n(ff, rd_buf, 5);
|
||||
TEST_ASSERT_EQUAL( 5, rd_count );
|
||||
TEST_ASSERT_EQUAL_MEMORY( test_data, rd_buf, rd_count ); // 0 -> 4
|
||||
|
||||
// case 2: Read index + count > depth
|
||||
// write 10, 11, 12
|
||||
tu_fifo_write(ff, test_data+FIFO_SIZE);
|
||||
tu_fifo_write(ff, test_data+FIFO_SIZE+1);
|
||||
tu_fifo_write(ff, test_data+FIFO_SIZE+2);
|
||||
|
||||
rd_count = tu_fifo_read_n(ff, rd_buf, 7);
|
||||
TEST_ASSERT_EQUAL( 7, rd_count );
|
||||
|
||||
TEST_ASSERT_EQUAL_MEMORY( test_data+5, rd_buf, rd_count ); // 5 -> 11
|
||||
|
||||
// Should only read until empty
|
||||
TEST_ASSERT_EQUAL( FIFO_SIZE-5+3-7, tu_fifo_read_n(ff, rd_buf, 100) );
|
||||
}
|
||||
|
||||
void test_write_n(void)
|
||||
{
|
||||
// case 1: wr + count < depth
|
||||
tu_fifo_write_n(ff, test_data, 32); // wr = 32, count = 32
|
||||
|
||||
uint16_t rd_count;
|
||||
|
||||
rd_count = tu_fifo_read_n(ff, rd_buf, 16); // wr = 32, count = 16
|
||||
TEST_ASSERT_EQUAL( 16, rd_count );
|
||||
TEST_ASSERT_EQUAL_MEMORY( test_data, rd_buf, rd_count );
|
||||
|
||||
// case 2: wr + count > depth
|
||||
tu_fifo_write_n(ff, test_data+32, 40); // wr = 72 -> 8, count = 56
|
||||
|
||||
tu_fifo_read_n(ff, rd_buf, 32); // count = 24
|
||||
TEST_ASSERT_EQUAL_MEMORY( test_data+16, rd_buf, rd_count);
|
||||
|
||||
TEST_ASSERT_EQUAL(24, tu_fifo_count(ff));
|
||||
}
|
||||
|
||||
void test_write_double_overflowed(void)
|
||||
{
|
||||
tu_fifo_set_overwritable(ff, true);
|
||||
|
||||
uint8_t rd_buf[FIFO_SIZE] = { 0 };
|
||||
uint8_t* buf = test_data;
|
||||
|
||||
// full
|
||||
buf += tu_fifo_write_n(ff, buf, FIFO_SIZE);
|
||||
TEST_ASSERT_EQUAL(FIFO_SIZE, tu_fifo_count(ff));
|
||||
|
||||
// write more, should still full
|
||||
buf += tu_fifo_write_n(ff, buf, FIFO_SIZE-8);
|
||||
TEST_ASSERT_EQUAL(FIFO_SIZE, tu_fifo_count(ff));
|
||||
|
||||
// double overflowed: in total, write more than > 2*FIFO_SIZE
|
||||
buf += tu_fifo_write_n(ff, buf, 16);
|
||||
TEST_ASSERT_EQUAL(FIFO_SIZE, tu_fifo_count(ff));
|
||||
|
||||
// reading back should give back data from last FIFO_SIZE write
|
||||
tu_fifo_read_n(ff, rd_buf, FIFO_SIZE);
|
||||
|
||||
TEST_ASSERT_EQUAL_MEMORY(buf-16, rd_buf+FIFO_SIZE-16, 16);
|
||||
|
||||
// TODO whole buffer should match, but we deliberately not implement it
|
||||
// TEST_ASSERT_EQUAL_MEMORY(buf-FIFO_SIZE, rd_buf, FIFO_SIZE);
|
||||
}
|
||||
|
||||
static uint16_t help_write(uint16_t total, uint16_t n)
|
||||
{
|
||||
tu_fifo_write_n(ff, test_data, n);
|
||||
total = tu_min16(FIFO_SIZE, total + n);
|
||||
|
||||
TEST_ASSERT_EQUAL(total, tu_fifo_count(ff));
|
||||
TEST_ASSERT_EQUAL(FIFO_SIZE - total, tu_fifo_remaining(ff));
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
void test_write_overwritable2(void)
|
||||
{
|
||||
tu_fifo_set_overwritable(ff, true);
|
||||
|
||||
// based on actual crash tests detected by fuzzing
|
||||
uint16_t total = 0;
|
||||
|
||||
total = help_write(total, 12);
|
||||
total = help_write(total, 55);
|
||||
total = help_write(total, 73);
|
||||
total = help_write(total, 55);
|
||||
total = help_write(total, 75);
|
||||
total = help_write(total, 84);
|
||||
total = help_write(total, 1);
|
||||
total = help_write(total, 10);
|
||||
total = help_write(total, 12);
|
||||
total = help_write(total, 25);
|
||||
total = help_write(total, 192);
|
||||
}
|
||||
|
||||
void test_peek(void)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
temp = 10; tu_fifo_write(ff, &temp);
|
||||
temp = 20; tu_fifo_write(ff, &temp);
|
||||
temp = 30; tu_fifo_write(ff, &temp);
|
||||
|
||||
temp = 0;
|
||||
|
||||
tu_fifo_peek(ff, &temp);
|
||||
TEST_ASSERT_EQUAL(10, temp);
|
||||
|
||||
tu_fifo_read(ff, &temp);
|
||||
tu_fifo_read(ff, &temp);
|
||||
|
||||
tu_fifo_peek(ff, &temp);
|
||||
TEST_ASSERT_EQUAL(30, temp);
|
||||
}
|
||||
|
||||
void test_get_read_info_when_no_wrap()
|
||||
{
|
||||
uint8_t ch = 1;
|
||||
|
||||
// write 6 items
|
||||
for(uint8_t i=0; i < 6; i++) tu_fifo_write(ff, &ch);
|
||||
|
||||
// read 2 items
|
||||
tu_fifo_read(ff, &ch);
|
||||
tu_fifo_read(ff, &ch);
|
||||
|
||||
tu_fifo_get_read_info(ff, &info);
|
||||
|
||||
TEST_ASSERT_EQUAL(4, info.len_lin);
|
||||
TEST_ASSERT_EQUAL(0, info.len_wrap);
|
||||
|
||||
TEST_ASSERT_EQUAL_PTR(ff->buffer+2, info.ptr_lin);
|
||||
TEST_ASSERT_NULL(info.ptr_wrap);
|
||||
}
|
||||
|
||||
void test_get_read_info_when_wrapped()
|
||||
{
|
||||
uint8_t ch = 1;
|
||||
|
||||
// make fifo full
|
||||
for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(ff, &ch);
|
||||
|
||||
// read 6 items
|
||||
for(uint8_t i=0; i < 6; i++) tu_fifo_read(ff, &ch);
|
||||
|
||||
// write 2 items
|
||||
tu_fifo_write(ff, &ch);
|
||||
tu_fifo_write(ff, &ch);
|
||||
|
||||
tu_fifo_get_read_info(ff, &info);
|
||||
|
||||
TEST_ASSERT_EQUAL(FIFO_SIZE-6, info.len_lin);
|
||||
TEST_ASSERT_EQUAL(2, info.len_wrap);
|
||||
|
||||
TEST_ASSERT_EQUAL_PTR(ff->buffer+6, info.ptr_lin);
|
||||
TEST_ASSERT_EQUAL_PTR(ff->buffer, info.ptr_wrap);
|
||||
}
|
||||
|
||||
void test_get_write_info_when_no_wrap()
|
||||
{
|
||||
uint8_t ch = 1;
|
||||
|
||||
// write 2 items
|
||||
tu_fifo_write(ff, &ch);
|
||||
tu_fifo_write(ff, &ch);
|
||||
|
||||
tu_fifo_get_write_info(ff, &info);
|
||||
|
||||
TEST_ASSERT_EQUAL(FIFO_SIZE-2, info.len_lin);
|
||||
TEST_ASSERT_EQUAL(0, info.len_wrap);
|
||||
|
||||
TEST_ASSERT_EQUAL_PTR(ff->buffer+2, info .ptr_lin);
|
||||
// application should check len instead of ptr.
|
||||
// TEST_ASSERT_NULL(info.ptr_wrap);
|
||||
}
|
||||
|
||||
void test_get_write_info_when_wrapped()
|
||||
{
|
||||
uint8_t ch = 1;
|
||||
|
||||
// write 6 items
|
||||
for(uint8_t i=0; i < 6; i++) tu_fifo_write(ff, &ch);
|
||||
|
||||
// read 2 items
|
||||
tu_fifo_read(ff, &ch);
|
||||
tu_fifo_read(ff, &ch);
|
||||
|
||||
tu_fifo_get_write_info(ff, &info);
|
||||
|
||||
TEST_ASSERT_EQUAL(FIFO_SIZE-6, info.len_lin);
|
||||
TEST_ASSERT_EQUAL(2, info.len_wrap);
|
||||
|
||||
TEST_ASSERT_EQUAL_PTR(ff->buffer+6, info .ptr_lin);
|
||||
TEST_ASSERT_EQUAL_PTR(ff->buffer, info.ptr_wrap);
|
||||
}
|
||||
|
||||
void test_empty(void)
|
||||
{
|
||||
uint8_t temp;
|
||||
TEST_ASSERT_TRUE(tu_fifo_empty(ff));
|
||||
|
||||
// read info
|
||||
tu_fifo_get_read_info(ff, &info);
|
||||
|
||||
TEST_ASSERT_EQUAL(0, info.len_lin);
|
||||
TEST_ASSERT_EQUAL(0, info.len_wrap);
|
||||
|
||||
TEST_ASSERT_NULL(info.ptr_lin);
|
||||
TEST_ASSERT_NULL(info.ptr_wrap);
|
||||
|
||||
// write info
|
||||
tu_fifo_get_write_info(ff, &info);
|
||||
|
||||
TEST_ASSERT_EQUAL(FIFO_SIZE, info.len_lin);
|
||||
TEST_ASSERT_EQUAL(0, info.len_wrap);
|
||||
|
||||
TEST_ASSERT_EQUAL_PTR(ff->buffer, info .ptr_lin);
|
||||
// application should check len instead of ptr.
|
||||
// TEST_ASSERT_NULL(info.ptr_wrap);
|
||||
|
||||
// write 1 then re-check empty
|
||||
tu_fifo_write(ff, &temp);
|
||||
TEST_ASSERT_FALSE(tu_fifo_empty(ff));
|
||||
}
|
||||
|
||||
void test_full(void)
|
||||
{
|
||||
TEST_ASSERT_FALSE(tu_fifo_full(ff));
|
||||
|
||||
for(uint8_t i=0; i < FIFO_SIZE; i++) tu_fifo_write(ff, &i);
|
||||
|
||||
TEST_ASSERT_TRUE(tu_fifo_full(ff));
|
||||
|
||||
// read info
|
||||
tu_fifo_get_read_info(ff, &info);
|
||||
|
||||
TEST_ASSERT_EQUAL(FIFO_SIZE, info.len_lin);
|
||||
TEST_ASSERT_EQUAL(0, info.len_wrap);
|
||||
|
||||
TEST_ASSERT_EQUAL_PTR(ff->buffer, info.ptr_lin);
|
||||
// skip this, application must check len instead of buffer
|
||||
// TEST_ASSERT_NULL(info.ptr_wrap);
|
||||
|
||||
// write info
|
||||
}
|
||||
|
||||
void test_rd_idx_wrap()
|
||||
{
|
||||
tu_fifo_t ff10;
|
||||
uint8_t buf[10];
|
||||
uint8_t dst[10];
|
||||
|
||||
tu_fifo_config(&ff10, buf, 10, 1, 1);
|
||||
|
||||
uint16_t n;
|
||||
|
||||
ff10.wr_idx = 6;
|
||||
ff10.rd_idx = 15;
|
||||
|
||||
n = tu_fifo_read_n(&ff10, dst, 4);
|
||||
TEST_ASSERT_EQUAL(n, 4);
|
||||
TEST_ASSERT_EQUAL(ff10.rd_idx, 0);
|
||||
n = tu_fifo_read_n(&ff10, dst, 4);
|
||||
TEST_ASSERT_EQUAL(n, 4);
|
||||
TEST_ASSERT_EQUAL(ff10.rd_idx, 4);
|
||||
n = tu_fifo_read_n(&ff10, dst, 4);
|
||||
TEST_ASSERT_EQUAL(n, 2);
|
||||
TEST_ASSERT_EQUAL(ff10.rd_idx, 6);
|
||||
}
|
||||
Reference in New Issue
Block a user