From 72a0ab9ff9748fe58f717a66bed068b3ec551293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thi=C3=A9baud=20Fuchs?= Date: Tue, 4 Jun 2024 13:52:27 +0200 Subject: [PATCH] Add stress test firmware to support Facedancer stress test --- tests/CMakeLists.txt | 3 +- .../test_firmware_usb_stress_test/.gitignore | 57 +++ tests/test_firmware_usb_stress_test/.ld | 1 + .../CMakeLists.txt | 101 ++++++ .../User/definitions.h | 32 ++ .../test_firmware_usb_stress_test/User/main.c | 324 ++++++++++++++++++ .../User/usb2_device_descriptors.h | 107 ++++++ .../User/usb_device.h | 209 +++++++++++ tests/test_firmware_usb_stress_test/format.sh | 3 + 9 files changed, 836 insertions(+), 1 deletion(-) create mode 100644 tests/test_firmware_usb_stress_test/.gitignore create mode 100644 tests/test_firmware_usb_stress_test/.ld create mode 100644 tests/test_firmware_usb_stress_test/CMakeLists.txt create mode 100644 tests/test_firmware_usb_stress_test/User/definitions.h create mode 100644 tests/test_firmware_usb_stress_test/User/main.c create mode 100644 tests/test_firmware_usb_stress_test/User/usb2_device_descriptors.h create mode 100644 tests/test_firmware_usb_stress_test/User/usb_device.h create mode 100644 tests/test_firmware_usb_stress_test/format.sh diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9c02f58..93e61bd 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,5 +5,6 @@ add_subdirectory(test_firmware_serdes) add_subdirectory(test_firmware_unittests) add_subdirectory(test_firmware_usb_loopback) add_subdirectory(test_firmware_usb_speedtest) -add_subdirectory(test_firmware_fifo) add_subdirectory(test_firmware_usb_loopback_separate_usb_stacks) +add_subdirectory(test_firmware_usb_stress_test) +add_subdirectory(test_firmware_fifo) diff --git a/tests/test_firmware_usb_stress_test/.gitignore b/tests/test_firmware_usb_stress_test/.gitignore new file mode 100644 index 0000000..0470403 --- /dev/null +++ b/tests/test_firmware_usb_stress_test/.gitignore @@ -0,0 +1,57 @@ +# Prerequisites +*.d + +# astyle generated +*.*.orig + +# Object files +*.o +*.ko +*.obj +*.elf +*.bin +*.lst + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf diff --git a/tests/test_firmware_usb_stress_test/.ld b/tests/test_firmware_usb_stress_test/.ld new file mode 100644 index 0000000..12f10dd --- /dev/null +++ b/tests/test_firmware_usb_stress_test/.ld @@ -0,0 +1 @@ +/* bvernoux 18June2022 => Changed SECTION ".DMADATA :" to ".DMADATA (NOLOAD) :" => Added in section ".DMADATA" => *(.DMADATA*) => To have a correct _dmadata_end (as before _dmadata_start was always equal to _dmadata_end) */ ENTRY( _start ) __stack_size = 2048; PROVIDE( _stack_size = __stack_size ); MEMORY { FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 448K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 16K RAMX (xrw) : ORIGIN = 0x20020000, LENGTH = 96K } SECTIONS { .init : { _sinit = .; . = ALIGN(4); KEEP(*(SORT_NONE(.init))) . = ALIGN(4); _einit = .; } >FLASH AT>FLASH .vector : { *(.vector); . = ALIGN(64); } >FLASH AT>FLASH .text : { . = ALIGN(4); *(.text) *(.text.*) *(.rodata) *(.rodata*) *(.glue_7) *(.glue_7t) *(.gnu.linkonce.t.*) . = ALIGN(4); } >FLASH AT>FLASH .fini : { KEEP(*(SORT_NONE(.fini))) . = ALIGN(4); } >FLASH AT>FLASH PROVIDE( _etext = . ); PROVIDE( _eitcm = . ); .preinit_array : { PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); } >FLASH AT>FLASH .init_array : { PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) PROVIDE_HIDDEN (__init_array_end = .); } >FLASH AT>FLASH .fini_array : { PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) PROVIDE_HIDDEN (__fini_array_end = .); } >FLASH AT>FLASH .ctors : { /* gcc uses crtbegin.o to find the start of the constructors, so we make sure it is first. Because this is a wildcard, it doesn't matter if the user does not actually link against crtbegin.o; the linker won't look for a file to match a wildcard. The wildcard also means that it doesn't matter which directory crtbegin.o is in. */ KEEP (*crtbegin.o(.ctors)) KEEP (*crtbegin?.o(.ctors)) /* We don't want to include the .ctor section from the crtend.o file until after the sorted ctors. The .ctor section from the crtend file contains the end of ctors marker and it must be last */ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } >FLASH AT>FLASH .dtors : { KEEP (*crtbegin.o(.dtors)) KEEP (*crtbegin?.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } >FLASH AT>FLASH .dalign : { . = ALIGN(4); PROVIDE(_data_vma = .); } >RAM AT>FLASH .dlalign : { . = ALIGN(4); PROVIDE(_data_lma = .); } >FLASH AT>FLASH .data : { *(.gnu.linkonce.r.*) *(.data .data.*) *(.gnu.linkonce.d.*) . = ALIGN(8); PROVIDE( __global_pointer$ = . + 0x800 ); *(.sdata .sdata.*) *(.sdata2.*) *(.gnu.linkonce.s.*) . = ALIGN(8); *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) . = ALIGN(4); PROVIDE( _edata = .); } >RAM AT>FLASH .bss : { . = ALIGN(4); PROVIDE( _sbss = .); *(.sbss*) *(.gnu.linkonce.sb.*) *(.bss*) *(.gnu.linkonce.b.*) *(COMMON*) . = ALIGN(4); PROVIDE( _ebss = .); } >RAM AT>FLASH PROVIDE( _end = _ebss); PROVIDE( end = . ); .DMADATA (NOLOAD) : { . = ALIGN(16); PROVIDE( _dmadata_start = .); *(.dmadata*) *(.dmadata.*) *(.DMADATA*) . = ALIGN(16); PROVIDE( _dmadata_end = .); } >RAMX AT>FLASH /**/ .stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size : { . = ALIGN(4); PROVIDE(_susrstack = . ); . = . + __stack_size; PROVIDE( _eusrstack = .); } >RAM } \ No newline at end of file diff --git a/tests/test_firmware_usb_stress_test/CMakeLists.txt b/tests/test_firmware_usb_stress_test/CMakeLists.txt new file mode 100644 index 0000000..a9f9297 --- /dev/null +++ b/tests/test_firmware_usb_stress_test/CMakeLists.txt @@ -0,0 +1,101 @@ +project(test_firmware_usb_stress_test LANGUAGES C) +set(CMAKE_EXECUTABLE_SUFFIX_C ".elf") + +add_executable(${PROJECT_NAME}) + +target_sources(${PROJECT_NAME} PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/User/main.c + ) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/User) + +##### Define program options + +#### wch-ch56x-lib options + +target_compile_definitions(wch-ch56x-lib-scheduled INTERFACE POOL_BLOCK_SIZE=512 POOL_BLOCK_NUM=40 INTERRUPT_QUEUE_SIZE=20) + +#### logging options + +# set(LOG_OUTPUT "printf") +# set(LOG_LEVEL 1) +# set(LOG_FILTER_IDS "1") + +if (DEFINED LOG_OUTPUT) + if (${LOG_OUTPUT} STREQUAL "buffer") + target_compile_definitions(${PROJECT_NAME} PRIVATE LOG_TYPE_BUFFER=1) + endif() + if (${LOG_OUTPUT} STREQUAL "serdes") + target_compile_definitions(${PROJECT_NAME} PRIVATE LOG_TYPE_SERDES=1) + endif() + if (${LOG_OUTPUT} STREQUAL "printf") + target_compile_definitions(${PROJECT_NAME} PRIVATE LOG_TYPE_PRINTF=1) + endif() +endif() + +if (DEFINED LOG_LEVEL) + target_compile_definitions(${PROJECT_NAME} PRIVATE LOG_LEVEL=${LOG_LEVEL}) +endif() + +if (DEFINED LOG_FILTER_IDS) + target_compile_definitions(${PROJECT_NAME} PRIVATE LOG_FILTER_IDS=${LOG_FILTER_IDS}) +endif() + +if (DEFINED STATIC_ANALYSIS) + target_compile_options(${PROJECT_NAME} PRIVATE -fanalyzer) +endif() + +##### Compilation and linkage options + +target_compile_options(${PROJECT_NAME} PRIVATE + -Werror -Warray-bounds=2 -Wno-comment -pedantic -Wall -Wno-error=unused-parameter + -Wbad-function-cast -Wredundant-decls -Wmissing-prototypes -Wchar-subscripts -Wshadow -Wundef -Wwrite-strings -Wunused -Wuninitialized -Wpointer-arith -Winline -Wformat -Wformat-security -Winit-self -Wmissing-include-dirs -Wnested-externs -Wmissing-declarations -Wempty-body -Wignored-qualifiers -Wmissing-field-initializers -Wtype-limits -Wcast-align -Wswitch-enum + -Wextra -Wclobbered -Wcast-function-type -Wimplicit-fallthrough=3 -Wmissing-parameter-type -Wold-style-declaration -Woverride-init -Wshift-negative-value -Wunused-but-set-parameter +) + +if (DEFINED EXTRACFLAGS) +target_compile_options(${PROJECT_NAME} PRIVATE + -Wunused-parameter -Wno-error=unused-parameter + -Wsign-compare -Wno-error=sign-compare + -Wconversion -Wno-error=conversion -Wno-error=sign-conversion -Wno-error=float-conversion +) +endif() + +if (${RISCV_GCC_TOOLCHAIN_PREFIX} STREQUAL "riscv-none-embed-gcc") + message("Using riscv-none-embed-gcc") + target_compile_options(${PROJECT_NAME} PRIVATE -march=rv32imac) +elseif(${RISCV_GCC_TOOLCHAIN_PREFIX} STREQUAL "riscv-none-elf-gcc") + message("Using riscv-none-elf-gcc") + target_compile_options(${PROJECT_NAME} PRIVATE -march=rv32imac_zicsr) +else() + message("Toolchain not found") +endif() + +target_compile_options(${PROJECT_NAME} PRIVATE -std=gnu99 -MMD -MP -mno-strict-align -mabi=ilp32 -msmall-data-limit=8 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections) +target_compile_options(${PROJECT_NAME} PRIVATE $<$:-Og> $<$:-Oz>) +target_link_options(${PROJECT_NAME} PRIVATE -T "${CMAKE_CURRENT_LIST_DIR}/.ld" -nostartfiles LINKER:--gc-sections LINKER:--print-memory-usage -Wl,-Map,${PROJECT_NAME}.map --specs=nano.specs --specs=nosys.specs) +target_link_libraries(${PROJECT_NAME} wch-ch56x-lib-scheduled) + +##### Generate additional targets + +add_custom_target(${PROJECT_NAME}.bin ALL DEPENDS ${PROJECT_NAME}.elf) +add_custom_target(${PROJECT_NAME}.hex ALL DEPENDS ${PROJECT_NAME}.elf) +add_custom_target(${PROJECT_NAME}.lst ALL DEPENDS ${PROJECT_NAME}.elf) + +add_custom_command(TARGET ${PROJECT_NAME}.bin + COMMAND ${CMAKE_OBJCOPY} -O binary ${PROJECT_NAME}.elf + ${PROJECT_NAME}.bin) + +add_custom_command(TARGET ${PROJECT_NAME}.hex + COMMAND ${CMAKE_OBJCOPY} -O ihex ${PROJECT_NAME}.elf + ${PROJECT_NAME}.hex) + +add_custom_command(TARGET ${PROJECT_NAME}.lst + COMMAND ${CMAKE_OBJDUMP} --source --all-headers --demangle --line-numbers --wide ${PROJECT_NAME}.elf > ${PROJECT_NAME}.lst) + +##### Export generated files + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.bin DESTINATION ${CMAKE_SOURCE_DIR}/out/${PROJECT_NAME}) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.hex DESTINATION ${CMAKE_SOURCE_DIR}/out/${PROJECT_NAME}) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.elf DESTINATION ${CMAKE_SOURCE_DIR}/out/${PROJECT_NAME}) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.lst DESTINATION ${CMAKE_SOURCE_DIR}/out/${PROJECT_NAME}) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.map DESTINATION ${CMAKE_SOURCE_DIR}/out/${PROJECT_NAME}) diff --git a/tests/test_firmware_usb_stress_test/User/definitions.h b/tests/test_firmware_usb_stress_test/User/definitions.h new file mode 100644 index 0000000..cef60e1 --- /dev/null +++ b/tests/test_firmware_usb_stress_test/User/definitions.h @@ -0,0 +1,32 @@ +/********************************** (C) COPYRIGHT ******************************* +Copyright (c) 2023 Quarkslab + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*******************************************************************************/ + +#ifndef DEFINITIONS_H +#define DEFINITIONS_H + +#define ENDP_1_15_MAX_PACKET_SIZE 1024 +/* Global define */ +// DEF_ENDP_OUT_BURST_LEVEL / DEF_ENDP_IN_BURST_LEVEL maximum burst size 16 +// defined by the USB3 specification Warning USB3 endpoint bulk with 8 or 16 +// burst can be problematic on some PC +#define DEF_ENDP_OUT_BURST_LEVEL 4 +#define DEF_ENDP_IN_BURST_LEVEL (DEF_ENDP_OUT_BURST_LEVEL) +#define DEF_ENDP_MAX_SIZE (DEF_ENDP1_OUT_BURST_LEVEL * 1024) + +#define MAX_TRANSFER_LENGTH 768 + +#endif \ No newline at end of file diff --git a/tests/test_firmware_usb_stress_test/User/main.c b/tests/test_firmware_usb_stress_test/User/main.c new file mode 100644 index 0000000..6b27dd8 --- /dev/null +++ b/tests/test_firmware_usb_stress_test/User/main.c @@ -0,0 +1,324 @@ +/********************************** (C) COPYRIGHT ******************************* +Copyright (c) 2023 Quarkslab + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*******************************************************************************/ + +// Disable warnings in bsp arising from -pedantic -Wall -Wconversion +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#pragma GCC diagnostic ignored "-Wvariadic-macros" +#pragma GCC diagnostic ignored "-Wsign-conversion" +#include "CH56x_common.h" +#include "CH56xSFR.h" +#pragma GCC diagnostic pop +#pragma GCC diagnostic pop +#pragma GCC diagnostic pop + +#include "usb2_device_descriptors.h" +#include "usb_device.h" +#include "wch-ch56x-lib/logging/logging.h" +#include "wch-ch56x-lib/USBDevice/usb20.h" +#include "wch-ch56x-lib/USBDevice/usb_descriptors.h" +#include "wch-ch56x-lib/USBDevice/usb_endpoints.h" + +#undef FREQ_SYS +/* System clock / MCU frequency in Hz (lowest possible speed 15MHz) */ +#define FREQ_SYS (120000000) + +#define MIN(a, b) (a <= b ? a : b) + +#define EP_IN 2 + +volatile bool nak_received = false; +volatile uint16_t in_transfer_length = 32; +volatile uint16_t in_transfer_total_sent = 0; +volatile uint16_t in_transfer_last_sent = 0; +volatile uint16_t out_total_sent = 0; +volatile uint16_t last_out_total_sent = 0; + +uint8_t last_out_buffer[ENDP_1_15_MAX_PACKET_SIZE * DEF_ENDP_OUT_BURST_LEVEL] + __attribute__((section(".DMADATA"))); +uint8_t temp_in_buffer[ENDP_1_15_MAX_PACKET_SIZE * DEF_ENDP_OUT_BURST_LEVEL] + __attribute__((section(".DMADATA"))); + +void generate_data(uint8_t* buffer, uint16_t length); +void generate_data(uint8_t* buffer, uint16_t length) +{ + for (uint16_t i = 0; i < length; ++i) + { + buffer[i] = i % 256; + } +} + +void endp2_tx_complete(TRANSACTION_STATUS status); +void endp2_tx_complete(TRANSACTION_STATUS status) +{ + nak_received = false; + in_transfer_total_sent += in_transfer_last_sent; +} + +uint8_t endp1_rx_callback(uint8_t* const ptr, uint16_t size); +uint8_t endp1_rx_callback(uint8_t* const ptr, uint16_t size) +{ + LOG("writing %d bytes %x %x %x %x \r\n", size, endp0_buffer[0], endp0_buffer[1], endp0_buffer[2], endp0_buffer[3]); + memcpy(last_out_buffer + out_total_sent, ptr, size); + out_total_sent += size; + last_out_total_sent = out_total_sent; //because no ZLP is sent for bulk OUT ... meaning we can't detect the end of the transfer + if (size < usb_device_0.endpoints.rx[1].max_packet_size || size == 0) + { + out_total_sent = 0; + } + return 0x00; +} + +void nak_callback(uint8_t endp_num); +void nak_callback(uint8_t endp_num) +{ + if (!nak_received && endp_num == EP_IN) + { + LOG("nak received \r\n"); + if (in_transfer_total_sent == in_transfer_length) + { + in_transfer_total_sent = 0; + } + nak_received = true; + in_transfer_last_sent = MIN(in_transfer_length - in_transfer_total_sent, usb_device_0.endpoints.tx[EP_IN].max_packet_size_with_burst); + memcpy(endp2_tx_buffer, temp_in_buffer + in_transfer_total_sent, in_transfer_last_sent); + endp_tx_set_new_buffer(&usb_device_0, EP_IN, endp2_tx_buffer, in_transfer_last_sent); + LOG("end nak received"); + } +} + +/* Blink time in ms */ +#define BLINK_FAST (50) // Blink LED each 100ms (50*2) +#define BLINK_USB3 (250) // Blink LED each 500ms (250*2) +#define BLINK_USB2 (1000) // Blink LED each 2000ms (1000*2) +int blink_ms = BLINK_USB2; +USB_DEVICE_SPEED usb_device_old_speed = -1; + +uint16_t endp0_user_handled_control_request(USB_SETUP* request, + uint8_t** buffer); +uint16_t endp0_user_handled_control_request(USB_SETUP* request, + uint8_t** buffer) +{ + if (request->bRequest == 10) + { + LOG("writing %x %x %x %x \r\n", endp0_buffer[0], endp0_buffer[1], endp0_buffer[2], endp0_buffer[3]); + memcpy(last_out_buffer, endp0_buffer, request->wLength); + last_out_total_sent = request->wLength; + return 0x00; + } + else if (request->bRequest == 20) + { + in_transfer_length = request->wValue.bw.bb1 | (request->wIndex.bw.bb1 << 8); + LOG("requested %d bytes \r\n", in_transfer_length); + generate_data(usb2_backend_current_device->endpoints.rx[0].buffer, in_transfer_length); + *buffer = usb2_backend_current_device->endpoints.rx[0].buffer; + return in_transfer_length; + } + else if (request->bRequest == 1) + { + in_transfer_length = request->wValue.bw.bb1 | (request->wIndex.bw.bb1 << 8); + LOG("in transfer length %d \r\n", in_transfer_length); + generate_data(temp_in_buffer, in_transfer_length); + in_transfer_total_sent = 0; + in_transfer_last_sent = 0; + return 0x00; + } + else if (request->bRequest == 2) + { + *buffer = last_out_buffer; + LOG("returning last out buffer %d\r\n", last_out_total_sent); + return last_out_total_sent; + } + else if (request->bRequest == 3) + { + LOG("reset out buffer head\r\n"); + out_total_sent = 0; + return 0x00; + } + return 0xffff; +} + +void usb2_device_handle_bus_reset(void); +void usb2_device_handle_bus_reset(void) +{ + LOG_IF_LEVEL(LOG_LEVEL_DEBUG, "bus reset \r\n"); +} +/********************************************************************* + * @fn main + * + * @brief Main program. + * + * @return none + */ +int main() +{ + // Initialize board + bsp_gpio_init(); + bsp_init(FREQ_SYS); + + LOG_INIT(FREQ_SYS); + LOG("USB stress test azeaez\r\n"); + + usb_device_0.endpoints.endp0_user_handled_control_request = endp0_user_handled_control_request; + usb_device_0.endpoints.tx_complete[2] = endp2_tx_complete; + usb_device_0.endpoints.rx_callback[1] = endp1_rx_callback; + usb_device_0.endpoints.nak_callback = nak_callback; + + usb2_user_handled.usb2_device_handle_bus_reset = + &usb2_device_handle_bus_reset; + + // Finish initializing the descriptor parameters + init_usb2_descriptors(); + init_string_descriptors(); + + // Set the USB device parameters + usb_device_set_usb2_device_descriptor(&usb_device_0, &usb2_descriptors.usb_device_descr); + usb_device_set_usb2_config_descriptors(&usb_device_0, usb2_device_configs); + usb_device_set_string_descriptors(&usb_device_0, device_string_descriptors); + usb_device_set_endpoint_mask(&usb_device_0, ENDPOINT_1_RX | ENDPOINT_2_TX); + + init_endpoints(); + + usb_device_0.speed = USB2_HIGHSPEED; + usb2_device_init(); + usb2_enable_nak(true); + + // Infinite loop USB2/USB3 managed with Interrupt + while (1) + { + if (bsp_ubtn()) + { + blink_ms = BLINK_FAST; + bsp_uled_on(); + bsp_wait_ms_delay(blink_ms); + bsp_uled_off(); + bsp_wait_ms_delay(blink_ms); + LOG_DUMP(); + } + else + { + if (usb_device_0.state == CONFIGURED) + { + switch (usb_device_0.speed) + { + case USB2_LOWSPEED: // USB2 + case USB2_FULLSPEED: + case USB2_HIGHSPEED: { + if (usb_device_0.speed != usb_device_old_speed) + { + usb_device_old_speed = usb_device_0.speed; + LOG_IF_LEVEL(LOG_LEVEL_DEBUG, "USB2\n"); + } + blink_ms = BLINK_USB2; + bsp_uled_on(); + bsp_wait_ms_delay(blink_ms); + bsp_uled_off(); + bsp_wait_ms_delay(blink_ms); + } + break; + case USB30_SUPERSPEED: // USB3 + { + if (usb_device_0.speed != usb_device_old_speed) + { + usb_device_old_speed = usb_device_0.speed; + LOG_IF_LEVEL(LOG_LEVEL_DEBUG, "USB3\n"); + } + blink_ms = BLINK_USB3; + bsp_uled_on(); + bsp_wait_ms_delay(blink_ms); + bsp_uled_off(); + bsp_wait_ms_delay(blink_ms); + } + break; + case SPEED_NONE: + default: + bsp_uled_on(); // LED is steady until USB3 SS or USB2 HS is ready + break; + } + } + else + { + bsp_uled_on(); // LED is steady until USB3 SS or USB2 HS is ready + } + } + } +} + +__attribute__((interrupt("WCH-Interrupt-fast"))) void WDOG_IRQHandler(void); +__attribute__((interrupt("WCH-Interrupt-fast"))) void WDOG_IRQHandler(void) +{ + LOG_DUMP(); + LOG_IF_LEVEL(LOG_LEVEL_CRITICAL, + "WDOG_IRQHandler\r\n" + " SP=0x%08X\r\n" + " MIE=0x%08X\r\n" + " MSTATUS=0x%08X\r\n" + " MCAUSE=0x%08X\r\n" + " MVENDORID=0x%08X\r\n" + " MARCHID=0x%08X\r\n" + " MISA=0x%08X\r\n" + " MIMPID=0x%08X\r\n" + " MHARTID=0x%08X\r\n" + " MEPC=0x%08X\r\n" + " MSCRATCH=0x%08X\r\n" + " MTVEC=0x%08X\r\n" + " MTVAL=0x%08X\r\n", + __get_SP(), __get_MIE(), __get_MSTATUS(), __get_MCAUSE(), + __get_MVENDORID(), __get_MARCHID(), __get_MISA(), __get_MIMPID(), + __get_MHARTID(), __get_MEPC(), __get_MSCRATCH(), __get_MTVEC(), __get_MTVAL()); + + LOG_DUMP(); + + bsp_wait_ms_delay(100000000); +} + +/********************************************************************* + * @fn HardFault_Handler + * + * @brief Example of basic HardFault Handler called if an exception occurs + * + * @return none + */ +__attribute__((interrupt("WCH-Interrupt-fast"))) void HardFault_Handler(void); +__attribute__((interrupt("WCH-Interrupt-fast"))) void HardFault_Handler(void) +{ + LOG_DUMP(); + LOG("this might be the return addr of current function %x \r\n", __builtin_return_address(0)); + // asm("ebreak"); to trigger a breakpoint and test hardfault_handler + LOG_IF_LEVEL(LOG_LEVEL_CRITICAL, + "HardFault_Handler\r\n" + " SP=0x%08X\r\n" + " MIE=0x%08X\r\n" + " MSTATUS=0x%08X\r\n" + " MCAUSE=0x%08X\r\n" + " MVENDORID=0x%08X\r\n" + " MARCHID=0x%08X\r\n" + " MISA=0x%08X\r\n" + " MIMPID=0x%08X\r\n" + " MHARTID=0x%08X\r\n" + " MEPC=0x%08X\r\n" + " MSCRATCH=0x%08X\r\n" + " MTVEC=0x%08X\r\n" + " MTVAL=0x%08X\r\n", + __get_SP(), __get_MIE(), __get_MSTATUS(), __get_MCAUSE(), + __get_MVENDORID(), __get_MARCHID(), __get_MISA(), __get_MIMPID(), + __get_MHARTID(), __get_MEPC(), __get_MSCRATCH(), __get_MTVEC(), __get_MTVAL()); + + LOG_DUMP(); + + bsp_wait_ms_delay(100000000); +} diff --git a/tests/test_firmware_usb_stress_test/User/usb2_device_descriptors.h b/tests/test_firmware_usb_stress_test/User/usb2_device_descriptors.h new file mode 100644 index 0000000..140f204 --- /dev/null +++ b/tests/test_firmware_usb_stress_test/User/usb2_device_descriptors.h @@ -0,0 +1,107 @@ +/********************************** (C) COPYRIGHT ******************************* +Copyright (c) 2023 Quarkslab + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*******************************************************************************/ + +#ifndef USB2_DEVICE_DESCRIPTOR_H +#define USB2_DEVICE_DESCRIPTOR_H + +#include "definitions.h" +#include "wch-ch56x-lib/USBDevice/usb_descriptors.h" + +const uint8_t* usb2_device_configs[1]; + +struct usb2_descriptors +{ + USB_DEV_DESCR usb_device_descr; + struct __PACKED + { + USB_CFG_DESCR usb_cfg_descr; + USB_ITF_DESCR usb_itf_descr; + USB_ENDP_DESCR usb_endp_descr_1; + USB_ENDP_DESCR usb_endp_descr_2_tx; + } other_descr; +} usb2_descriptors; + +void init_usb2_descriptors(void); + +void init_usb2_descriptors(void) +{ + usb2_descriptors.usb_device_descr = (USB_DEV_DESCR){ + .bLength = 0x12, + .bDescriptorType = 0x01, // device descriptor type + .bcdUSB = 0x0200, // usb2.0 + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize0 = 64, + .bcdDevice = 0x0001, + .idVendor = + 0x1209, // https://github.com/obdev/v-usb/blob/master/usbdrv/usb-ids-for-free.txt + .idProduct = 0x0001, + .iProduct = 0x01, + .iManufacturer = 0x00, + .iSerialNumber = 0x00, + .bNumConfigurations = 0x01 + }; + + usb2_descriptors.other_descr.usb_cfg_descr = (USB_CFG_DESCR){ + .bLength = 0x09, + .bDescriptorType = 0x02, + .wTotalLength = sizeof(usb2_descriptors.other_descr), + .bNumInterfaces = 0x01, + .bConfigurationValue = 0x01, + .iConfiguration = 0x00, + .bmAttributes = 0xa0, // supports remote wake-up + .MaxPower = 0x64 // 200ma + }; + + usb2_descriptors.other_descr.usb_itf_descr = + (USB_ITF_DESCR){ .bLength = 0x09, + .bDescriptorType = 0x04, + .bInterfaceNumber = 0x00, + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x02, + .bInterfaceClass = 0xff, // vendor-specific + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .iInterface = 0x00 }; + + usb2_descriptors.other_descr.usb_endp_descr_1 = (USB_ENDP_DESCR){ + .bLength = 0x07, + .bDescriptorType = 0x05, + .bEndpointAddress = (ENDPOINT_DESCRIPTOR_ADDRESS_OUT | 0x01) & + ENDPOINT_DESCRIPTOR_ADDRESS_MASK, + .bmAttributes = ENDPOINT_DESCRIPTOR_BULK_TRANSFER, + .wMaxPacketSizeL = 0x00, + .wMaxPacketSizeH = 0x02, // 512 bytes + .bInterval = 255 // max NAK rate + }; + + usb2_descriptors.other_descr.usb_endp_descr_2_tx = (USB_ENDP_DESCR){ + .bLength = 0x07, + .bDescriptorType = 0x05, + .bEndpointAddress = (ENDPOINT_DESCRIPTOR_ADDRESS_IN | 0x02) & + ENDPOINT_DESCRIPTOR_ADDRESS_MASK, + .bmAttributes = ENDPOINT_DESCRIPTOR_BULK_TRANSFER, + .wMaxPacketSizeL = 0x00, + .wMaxPacketSizeH = 0x02, // 512 bytes + .bInterval = 0 + }; + + usb2_device_configs[0] = (uint8_t*)&usb2_descriptors.other_descr; +} + +#endif diff --git a/tests/test_firmware_usb_stress_test/User/usb_device.h b/tests/test_firmware_usb_stress_test/User/usb_device.h new file mode 100644 index 0000000..2d9efce --- /dev/null +++ b/tests/test_firmware_usb_stress_test/User/usb_device.h @@ -0,0 +1,209 @@ +/********************************** (C) COPYRIGHT ******************************* +Copyright (c) 2023 Quarkslab + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*******************************************************************************/ + +#ifndef USB_DEVICE_USER_H +#define USB_DEVICE_USER_H + +#include "definitions.h" +#include "wch-ch56x-lib/USBDevice/usb_descriptors.h" +#include "wch-ch56x-lib/USBDevice/usb_device.h" +#include "wch-ch56x-lib/USBDevice/usb_endpoints.h" + +uint8_t hydradancer_product_string_descriptor[] = { + 'H', + 0x00, + 'y', + 0x00, + 'd', + 0x00, + 'r', + 0x00, + 'a', + 0x00, + 'd', + 0x00, + 'a', + 0x00, + 'n', + 0x00, + 'c', + 0x00, + 'e', + 0x00, + 'r', + 0x00, + ' ', + 0x00, + 'T', + 0x00, + 'e', + 0x00, + 's', + 0x00, + 't', + 0x00, + ' ', + 0x00, + 'F', + 0x00, + 'i', + 0x00, + 'r', + 0x00, + 'm', + 0x00, + 'w', + 0x00, + 'a', + 0x00, + 'r', + 0x00, + 'e', + 0x00, + ',', + 0x00, + ' ', + 0x00, + 'b', + 0x00, + 'i', + 0x00, + 'd', + 0x00, + 'i', + 0x00, + 'r', + 0x00, + 'e', + 0x00, + 'c', + 0x00, + 't', + 0x00, + 'i', + 0x00, + 'o', + 0x00, + 'n', + 0x00, + 'n', + 0x00, + 'a', + 0x00, + 'l', + 0x00, + ',', + 0x00, + ' ', + 0x00, + 'a', + 0x00, + 'l', + 0x00, + 'l', + 0x00, + ' ', + 0x00, + 'e', + 0x00, + 'n', + 0x00, + 'd', + 0x00, + 'p', + 0x00, + 'o', + 0x00, + 'i', + 0x00, + 'n', + 0x00, + 't', + 0x00, + 's', + 0x00, +}; + +struct usb_string_descriptors +{ + USB_STRING_DESCR lang_ids_descriptor; + uint16_t lang_ids[1]; + USB_STRING_DESCR product_string_descriptor; + uint8_t hydradancer_product_string_descriptor[sizeof( + hydradancer_product_string_descriptor)]; +} usb_string_descriptors; + +const USB_STRING_DESCR* device_string_descriptors[2]; + +__attribute__((aligned(16))) +uint8_t endp0_buffer[MAX_TRANSFER_LENGTH] + __attribute__((section(".DMADATA"))); +__attribute__((aligned(16))) + +uint8_t endp1_rx_buffer[ENDP_1_15_MAX_PACKET_SIZE * DEF_ENDP_OUT_BURST_LEVEL] + __attribute__((section(".DMADATA"))); + +__attribute__((aligned(16))) +uint8_t endp2_tx_buffer[ENDP_1_15_MAX_PACKET_SIZE * DEF_ENDP_IN_BURST_LEVEL] + __attribute__((section(".DMADATA"))); + +void init_string_descriptors(void); +void init_string_descriptors(void) +{ + usb_string_descriptors.lang_ids_descriptor = (USB_STRING_DESCR){ + .bLength = + sizeof(USB_STRING_DESCR) + sizeof(usb_string_descriptors.lang_ids), + .bDescriptorType = 0x03, // String Descriptor + }; + + usb_string_descriptors.lang_ids[0] = 0x0409; + + usb_string_descriptors.product_string_descriptor = (USB_STRING_DESCR){ + .bLength = sizeof(USB_STRING_DESCR) + + sizeof(hydradancer_product_string_descriptor), + .bDescriptorType = 0x03, // String Descriptor + }; + + memcpy(&usb_string_descriptors.hydradancer_product_string_descriptor, + hydradancer_product_string_descriptor, + sizeof(hydradancer_product_string_descriptor)); + + device_string_descriptors[0] = &usb_string_descriptors.lang_ids_descriptor; + device_string_descriptors[1] = + &usb_string_descriptors.product_string_descriptor; +} + +void init_endpoints(void); +void init_endpoints(void) +{ + usb_device_0.endpoints.rx[0].buffer = endp0_buffer; + usb_device_0.endpoints.rx[0].max_packet_size = 512; + usb_device_0.endpoints.rx[0].max_burst = 1; + usb_device_0.endpoints.rx[0].max_packet_size_with_burst = 512; + + usb_device_0.endpoints.rx[1].buffer = endp1_rx_buffer; + usb_device_0.endpoints.rx[1].max_packet_size = 512; + usb_device_0.endpoints.rx[1].max_burst = 4; + usb_device_0.endpoints.rx[1].max_packet_size_with_burst = 512; + + usb_device_0.endpoints.tx[2].buffer = NULL; + usb_device_0.endpoints.tx[2].max_packet_size = 512; + usb_device_0.endpoints.tx[2].max_burst = 4; + usb_device_0.endpoints.tx[2].max_packet_size_with_burst = 512; +} + +#endif diff --git a/tests/test_firmware_usb_stress_test/format.sh b/tests/test_firmware_usb_stress_test/format.sh new file mode 100644 index 0000000..6ec4ecb --- /dev/null +++ b/tests/test_firmware_usb_stress_test/format.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +find ./User \( -iname "*.h" -o -iname "*.c" \) -print0 | xargs -0 clang-format --verbose --style=file -i;