diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4538604..b827e22 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,18 +2,18 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.2.0 + rev: v4.6.0 hooks: - id: trailing-whitespace - id: check-yaml - id: check-added-large-files - id: check-merge-conflict - repo: https://github.com/hhatto/autopep8 - rev: v2.0.4 + rev: v2.3.1 hooks: - id: autopep8 - repo: https://github.com/pylint-dev/pylint - rev: v3.0.2 + rev: v3.2.5 hooks: - id: pylint - repo: https://github.com/pre-commit/mirrors-clang-format diff --git a/BUILD.md b/BUILD.md index 0ca1d28..def4f17 100644 --- a/BUILD.md +++ b/BUILD.md @@ -90,9 +90,11 @@ Currently, you need two HydraUSB3 boards connected together via HSPI. You just n To be able to access the HydraDancer boards and flash them, root privileges may be required, or you can provide them to your regular user, e.g. with the creation of a file `/etc/udev/rules.d/99-hydrausb3.rules` with ``` -# UDEV Rules for HydraUSB3 boards, https://github.com/hydrausb3 +# UDEV Rules for HydraUSB3 boards https://github.com/hydrausb3, Hydradancer https://github.com/HydraDancer/hydradancer_fw and Facedancer https://github.com/greatscottgadgets/Facedancer # WinChipHead CH569W Bootloader SUBSYSTEMS=="usb", ATTRS{idVendor}=="4348", ATTRS{idProduct}=="55e0", MODE="0664", GROUP="plugdev" +# Hydradancer +SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="27d8", MODE="0664", GROUP="plugdev" ``` and having your user as member of the group `plugdev`. diff --git a/README.md b/README.md index 249bbe6..0f72d45 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,122 @@ Hydradancer provides a faster, USB2 High-Speed capable backend for Facedancer by taking advantage of fast communication protocols such as USB3, SerDes and HSPI. +The following examples have been confirmed working: +* hackrf-info.py +* imperative.py +* mass-storage.py +* minimal.py (with test_minimal.py) +* rubber-ducky.py +* template.py +* usbproxy.py : USB Flash Drive in USB2 High-Speed + +**DISCLAIMER** : current results for the [highly-stressed stress test of Facedancer](https://github.com/greatscottgadgets/facedancer/blob/main/test/test_stress.py) with 20000 tries. + +The current Facedancer stress test results are the following. +* USB2 High-Speed + * bulk IN/ctrl IN : pass + * bulk OUT/ctrl OUT : fails after a few hundred/thousand tries, never reaches 20000 +* USB2 Full-Speed + * bulk IN/ctrl IN : fails after a few hundred/thousand tries, never reaches 20000 + * bulk OUT/ctrl OUT : fails after a few hundred/thousand tries, never reaches 20000 + +We are currently working on fixing those issues and we have a few culprits in mind : +* missed interrupts : the main culprit for now, it puts Hydradancer in a blocked state. +* differences between HS/FS : HS has PING packets which reduces the amount of data transfers for OUT transactions. Since there are no FS examples from WCH and no indications in the datasheet, we experimented to solve this issue. + +We implemented a [firmware](https://github.com/hydrausb3/wch-ch56x-lib/tree/main/tests/test_firmware_usb_stress_test) to test the USB2 implementation of `wch-ch56x-lib` with the same stress test and it passes with 100000 tries in both HS and FS. However, Hydradancer's firmware is more complex (more interrupts, USB3 and USB2 at the same time, delays to synchronize with Facedancer). + +# Getting started (Hydradancer dongle) + +1. To be able to access the HydraDancer boards and flash them, root privileges may be required, or you can provide them to your regular user, e.g. with the creation of a file `/etc/udev/rules.d/99-hydradancer.rules` with + +``` +# UDEV Rules for HydraUSB3 boards https://github.com/hydrausb3, Hydradancer https://github.com/HydraDancer/hydradancer_fw and Facedancer https://github.com/greatscottgadgets/Facedancer +# WinChipHead CH569W Bootloader +SUBSYSTEMS=="usb", ATTRS{idVendor}=="4348", ATTRS{idProduct}=="55e0", MODE="0664", GROUP="plugdev" +# Hydradancer +SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="27d8", MODE="0664", GROUP="plugdev" +``` + +and having your user as member of the group `plugdev`. + +2. Flash the firmware to your Hydradancer dongle using the [latest release](https://github.com/HydraDancer/hydradancer_fw/releases/latest) (download `all-firmwares*.zip`) with [wch-ch56-isp](https://github.com/hydrausb3/wch-ch56x-isp/releases/latest) + +First + +``` +Put the Hydradancer dongle in firmware download mode. For that, you need the following buttons : +* reset : button with "RST" next to it +* flash mode : button with "Flash Mode" next to it + +You need to hold the flash mode button, press reset and then release the flash mode button. +``` + +Then, launch `wch-ch56x-isp` + +```shell +wch-ch56x-isp -vf firmware_hydradancer.bin +``` + +3. Install Facedancer + +Clone our Facedancer work + +```shell +https://github.com/HydraDancer/Facedancer +``` + +Then, reuse your virtual env or create a new one to keep your local Python installation clean + +```shell +sudo apt install python3 python3-venv +python3 -m venv venv +``` + +Activate the venv + +```shell +source venv/bin/activate +``` + +Install Facedancer + +```shell +cd Facedancer +pip install --editable . +``` + +The `--editable` isn't necessary but it allows you to modify Facedancer's files. + +4. Test one of the examples + +Then, tell Facedancer to use the Hydradancer backend + +```shell +export BACKEND=hydradancer +``` + +And finally, run one of the examples to check if everything works + +```shell +python3 ./examples/rubber-ducky.py +``` + +To test the proxy mode of Facedancer, you might need to use the following line (after editing `usbproxy.py` with the target vid/pid) + +```shell +sudo sh -c "env BACKEND=hydradancer ./venv/bin/python3 examples/usbproxy.py" +``` + # Comparison with other Facedancer boards -As shown in the table below, Hydradancer currently supports 5 endpoints other than endpoint 0 in either the IN or OUT directions, with numbers between 1-7. Hydradancer can also emulate USB2 High-speed peripherals. Host mode is currently unsupported, but could be implemented if needed. +As shown in the table below, Hydradancer currently supports 5 endpoints other than endpoint 0 in either the IN or OUT directions, with numbers between 1-15. Hydradancer can also emulate USB2 High-speed peripherals. Host mode is currently unsupported, but could be implemented if needed. |Board|Maximum speed |Number of endpoints (not EP0) |Host mode| |:---:|:----:|:-:|:-:| Facedancer21/Raspdancer |USB2 Full-speed |EP1 OUT, EP2 IN, EP3 IN |yes| GreatFET One |USB2 Full-speed |3 IN / 3 OUT |yes| -**Hydradancer** |USB2 High-speed |6 IN / 6 OUT |no| +**Hydradancer** |USB2 High-speed |5 IN / 5 OUT |no| (Cynthion/LUNA)(coming early 2024) |(USB2 High-speed) |(15 IN / 15 OUT) |(yes)|
Facedancer backends functionalities
@@ -103,67 +210,18 @@ Previous results for Hydradancer used priming, which made it faster. The new ver There are two configurations for Hydradancer: * the Hydradancer dongle : only the firmware from `hydradancer/firmware_hydradancer` is needed. -* (unmaintained) the dual-HydraUSB3 : you will need the firmware compiled from `hydradancer/firmware_control_board` and `hydradancer/firmware_emulation_board`. +* (unmaintained) the dual-HydraUSB3 : you will need the firmware compiled from `legacy/hydradancer/firmware_control_board` and `legacy/hydradancer/firmware_emulation_board`. To build and flash the firmware, see [the build tutorial](BUILD.md). If you don't want to build the firmwares yourself, you can skip the building part by using the [latest release](https://github.com/HydraDancer/hydradancer_fw/releases/latest). -# ... and finally, using Facedancer with Hydradancer ! - -First, clone Facedancer. While we hope to merge the Hydradancer backend for Facedancer into the [main repository](https://github.com/greatscottgadgets/Facedancer) along with some bug fixes we may have found, the Hydradancer backend is currently in our fork. - -For the unmaintained dual-HydraUSB3 firmware, you will need v1.0.0 of our Facedancer fork. - -```shell -git clone https://github.com/HydraDancer/Facedancer -``` - -Then, reuse your virtual env or create a new one to keep your local Python installation clean - -```shell -sudo apt install python3 python3-venv -python3 -m venv venv -``` - -Activate the venv - -```shell -source venv/bin/activate -``` - -Install Facedancer - -```shell -cd Facedancer -pip install --editable . -``` - -The `--editable` isn't necessary but it allows you to modify Facedancer's files. - -Then, tell Facedancer to use the Hydradancer backend - -```shell -export BACKEND=hydradancer -``` - -And finally, run one of the examples to check if everything works, this one should make your cursor wiggle. - -```shell -python3 ./examples/crazy-mouse.py -``` - -More information on the different peripherals that can be emulated can be found in `docs/Facedancer.md` - -_Note for the dual-HydraUSB3 configuration: you might need to reset both boards after flashing the firmwares (control board first, then emulation board), or if any problem arises when running the scripts._ - # Structure of the project ``` hydradancer/ -| ├─ firmware_control_board # firmware for the board connected to Facedancer, dual-HydraUSB3 configuration -| ├─ firmware_emulation_board # firmware for the board connected to the target USB port, dual-HydraUSB3 configuration | ├─ firmware_hydradancer # firmware for the Hydradancer dongle +| ├─ legacy/ # old HydraUSB3 firmwares, unmaintained | ├─ tests/ # test firmwares to create various USB devices -| | ├─ test_backend # Test a Facedancer-like configuration, but without Facedancer. Not up-to-date. +| | ├─ test_backend # Not up-to-date. Test a Facedancer-like configuration, but without Facedancer. | | ├─ native/ # C programs using libusb to interact with the test firmwares | | ├─ scripts/ # Python scripts using pyusb to interact with the test firmwares tools/ diff --git a/docs/Testing.md b/docs/Testing.md index 5b1fb46..b6d20ba 100644 --- a/docs/Testing.md +++ b/docs/Testing.md @@ -41,7 +41,7 @@ Different firmwares have been created, along with Python scripts to execute the Below are the different test cases and how to test them: -### Backend speedtest +### (unmaintained) Backend speedtest * Compile : * compile `test_backend/firmware_emulation_board` and `HydraDancer/hydradancer/firmware_control_board` with `make` diff --git a/hydradancer/firmware_hydradancer/User/definitions.h b/hydradancer/firmware_hydradancer/User/definitions.h index fca3239..8c440d0 100644 --- a/hydradancer/firmware_hydradancer/User/definitions.h +++ b/hydradancer/firmware_hydradancer/User/definitions.h @@ -16,11 +16,6 @@ #include "wch-ch56x-lib/USBDevice/usb_device.h" #include "wch-ch56x-lib/USBDevice/usb_endpoints.h" -#define CUSTOM_REGISTER_ENDPOINT_MASK 0x000f -#define CUSTOM_REGISTER_REQUEST_CODE_BIT_MASK 0x0010 -#define CUSTOM_REGISTER_REQUEST_CODE_MASK 0x01e0 -#define CUSTOM_REGISTER_REQUEST_CODE_OFFSET 0x5 - #define USB2_LS 0x00 #define USB2_FS 0x01 #define USB2_HS 0x02 @@ -53,10 +48,10 @@ typedef struct __attribute__((packed)) { - uint8_t ep_in_status; - uint8_t ep_out_status; - uint8_t ep_in_nak; - uint8_t other_events; + uint16_t ep_in_status; + uint16_t ep_out_status; + uint16_t ep_in_nak; + uint16_t other_events; } hydradancer_status_t; typedef struct __attribute__((packed)) @@ -65,7 +60,7 @@ typedef struct __attribute__((packed)) uint8_t value; } hydradancer_event_t; -#define MAX_ENDPOINTS_SUPPORTED 8 //including EP0 +#define MAX_ENDPOINTS_SUPPORTED 16 //including EP0 extern uint8_t endpoint_mapping_reverse[MAX_ENDPOINTS_SUPPORTED]; //endpoint_mapping_reverse[PC_Endpoint] = Target_Endpoint extern uint8_t endpoint_mapping[MAX_ENDPOINTS_SUPPORTED]; //endpoint_mapping[Target_Endpoint] = PC_Endpoint extern __attribute__((aligned(16))) volatile hydradancer_status_t hydradancer_status __attribute__((section(".DMADATA"))); @@ -147,11 +142,14 @@ __attribute__((always_inline)) inline static void hydradancer_status_clear_nak(u __attribute__((always_inline)) inline static void hydradancer_recover_out_interrupt(uint8_t endp_num) { - ramx_pool_free(usb_device_1.endpoints.tx[endpoint_mapping[endp_num]].buffer); - hydradancer_status_clear_out(endp_num); - bsp_disable_interrupt(); - endp_rx_set_state(&usb_device_0, endp_num, ENDP_STATE_ACK); - bsp_enable_interrupt(); + if (hydradancer_status.ep_out_status & (0x01 << endpoint_mapping_reverse[endp_num])) + { + ramx_pool_free(usb_device_1.endpoints.tx[endpoint_mapping[endp_num]].buffer); + hydradancer_status_clear_out(endp_num); + bsp_disable_interrupt(); + endp_rx_set_state(&usb_device_0, endp_num, ENDP_STATE_ACK); + bsp_enable_interrupt(); + } } #endif diff --git a/hydradancer/firmware_hydradancer/User/main.c b/hydradancer/firmware_hydradancer/User/main.c index 560707d..69a5c46 100644 --- a/hydradancer/firmware_hydradancer/User/main.c +++ b/hydradancer/firmware_hydradancer/User/main.c @@ -102,6 +102,14 @@ int main() usb_device_0.endpoints.tx_complete[5] = usb_emulation_endp5_tx_complete; usb_device_0.endpoints.tx_complete[6] = usb_emulation_endp6_tx_complete; usb_device_0.endpoints.tx_complete[7] = usb_emulation_endp7_tx_complete; + usb_device_0.endpoints.tx_complete[8] = usb_emulation_endp7_tx_complete; + usb_device_0.endpoints.tx_complete[9] = usb_emulation_endp7_tx_complete; + usb_device_0.endpoints.tx_complete[10] = usb_emulation_endp7_tx_complete; + usb_device_0.endpoints.tx_complete[11] = usb_emulation_endp7_tx_complete; + usb_device_0.endpoints.tx_complete[12] = usb_emulation_endp7_tx_complete; + usb_device_0.endpoints.tx_complete[13] = usb_emulation_endp7_tx_complete; + usb_device_0.endpoints.tx_complete[14] = usb_emulation_endp7_tx_complete; + usb_device_0.endpoints.tx_complete[15] = usb_emulation_endp7_tx_complete; usb_device_0.endpoints.rx_callback[0] = usb_emulation_endp0_rx_callback; usb_device_0.endpoints.rx_callback[1] = usb_emulation_endp1_rx_callback; usb_device_0.endpoints.rx_callback[2] = usb_emulation_endp2_rx_callback; @@ -110,6 +118,14 @@ int main() usb_device_0.endpoints.rx_callback[5] = usb_emulation_endp5_rx_callback; usb_device_0.endpoints.rx_callback[6] = usb_emulation_endp6_rx_callback; usb_device_0.endpoints.rx_callback[7] = usb_emulation_endp7_rx_callback; + usb_device_0.endpoints.rx_callback[8] = usb_emulation_endp7_rx_callback; + usb_device_0.endpoints.rx_callback[9] = usb_emulation_endp7_rx_callback; + usb_device_0.endpoints.rx_callback[10] = usb_emulation_endp7_rx_callback; + usb_device_0.endpoints.rx_callback[11] = usb_emulation_endp7_rx_callback; + usb_device_0.endpoints.rx_callback[12] = usb_emulation_endp7_rx_callback; + usb_device_0.endpoints.rx_callback[13] = usb_emulation_endp7_rx_callback; + usb_device_0.endpoints.rx_callback[14] = usb_emulation_endp7_rx_callback; + usb_device_0.endpoints.rx_callback[15] = usb_emulation_endp7_rx_callback; usb_device_0.endpoints.nak_callback = usb_emulation_nak_callback; usb2_user_handled.usb2_device_handle_bus_reset = usb_emulation_usb2_device_handle_bus_reset; @@ -124,7 +140,6 @@ int main() usb_device_set_string_descriptors(&usb_device_0, NULL); // Set the USB device parameters usb2_ep0_passthrough_enabled(true); - usb_device_set_endpoint_mask(&usb_device_0, ENDPOINT_1_RX | ENDPOINT_1_TX | ENDPOINT_2_RX | ENDPOINT_2_TX | ENDPOINT_3_RX | ENDPOINT_3_TX | ENDPOINT_4_RX | ENDPOINT_4_TX | ENDPOINT_5_RX | ENDPOINT_5_TX | ENDPOINT_6_RX | ENDPOINT_6_TX | ENDPOINT_7_RX | ENDPOINT_7_TX); usb_emulation_init_endpoints(); //=================== Finished initializing Emulation device =====================// diff --git a/hydradancer/firmware_hydradancer/User/usb_control_handlers.h b/hydradancer/firmware_hydradancer/User/usb_control_handlers.h index 162f69f..087aa4c 100644 --- a/hydradancer/firmware_hydradancer/User/usb_control_handlers.h +++ b/hydradancer/firmware_hydradancer/User/usb_control_handlers.h @@ -19,21 +19,24 @@ #include "wch-ch56x-lib/USBDevice/usb20.h" #include "wch-ch56x-lib/USBDevice/usb2_utils.h" #include "wch-ch56x-lib/USBDevice/usb30.h" +#include "wch-ch56x-lib/USBDevice/usb30_utils.h" #include "wch-ch56x-lib/USBDevice/usb_descriptors.h" #include "wch-ch56x-lib/USBDevice/usb_endpoints.h" #include "wch-ch56x-lib/USBDevice/usb_types.h" -void usb_control_endp1_tx_complete(TRANSACTION_STATUS status); -void usb_control_endp1_tx_complete(TRANSACTION_STATUS status) +__attribute__((always_inline)) static inline void usb_control_endp1_tx_complete(TRANSACTION_STATUS status) { event_transfer_finished = true; } __attribute__((always_inline)) static inline void usb_control_endp_tx_complete(TRANSACTION_STATUS status, uint8_t endp_num) { - ramx_pool_free(usb_device_1.endpoints.tx[endp_num].buffer); - hydradancer_status_clear_out(endpoint_mapping_reverse[endp_num]); - endp_rx_set_state(&usb_device_0, endpoint_mapping_reverse[endp_num], ENDP_STATE_ACK); + if (hydradancer_status.ep_out_status & (0x01 << endpoint_mapping_reverse[endp_num])) + { + ramx_pool_free(usb_device_1.endpoints.tx[endp_num].buffer); + hydradancer_status_clear_out(endpoint_mapping_reverse[endp_num]); + endp_rx_set_state(&usb_device_0, endpoint_mapping_reverse[endp_num], ENDP_STATE_ACK); + } } void usb_control_endp2_tx_complete(TRANSACTION_STATUS status); @@ -84,7 +87,16 @@ static bool _usb_control_endp_rx_callback(uint8_t* data); static bool _usb_control_endp_rx_callback(uint8_t* data) { ep_queue_member_t* ep_queue_member = (ep_queue_member_t*)data; + while (true) + { + bsp_disable_interrupt(); + volatile uint16_t status = hydradancer_status.ep_in_status; + bsp_enable_interrupt(); + if (status & (0x01 << endpoint_mapping_reverse[ep_queue_member->ep_num])) + break; + } endp_tx_set_new_buffer(&usb_device_0, endpoint_mapping_reverse[ep_queue_member->ep_num], ep_queue_member->ptr, ep_queue_member->size); + hydradancer_status_set_in(endpoint_mapping_reverse[ep_queue_member->ep_num]); return true; } @@ -112,7 +124,6 @@ __attribute__((always_inline)) static inline uint8_t usb_control_endp_rx_callbac ep_queue_member->size = size; hydra_interrupt_queue_set_next_task(_usb_control_endp_rx_callback, (uint8_t*)ep_queue_member, _ep_queue_cleanup); usb_device_1.endpoints.rx[ep_queue_member->ep_num].buffer = buffer; - hydradancer_status.ep_in_status &= ~(0x01 << endpoint_mapping_reverse[ep_queue_member->ep_num]); return ENDP_STATE_ACK; } @@ -194,12 +205,18 @@ uint16_t usb_control_endp0_user_handled_control_request(USB_SETUP* request, uint } else if (request->bRequest == SET_ENDPOINT_MAPPING) { - LOG_IF(LOG_LEVEL_DEBUG, LOG_ID_USER, "SET_ENDPOINT_MAPPING target_ep %d pc_ep %d \r\n", request->wValue.bw.bb1, request->wValue.bw.bb0); + LOG("SET_ENDPOINT_MAPPING target_ep %d pc_ep %d \r\n", request->wValue.bw.bb1, request->wValue.bw.bb0); endpoint_mapping[request->wValue.bw.bb1] = request->wValue.bw.bb0; endpoint_mapping_reverse[request->wValue.bw.bb0] = request->wValue.bw.bb1; hydradancer_status.ep_in_status |= (0x01 << request->wValue.bw.bb1); hydradancer_status.ep_out_status &= ~(0x01 << request->wValue.bw.bb1); usb_device_0.endpoints.rx[request->wValue.bw.bb1].max_packet_size = usb_device_0.speed == USB2_HIGHSPEED ? 512 : 64; + if (request->wValue.bw.bb1 > 0) + { + uint32_t new_eps = ((1U << ((request->wValue.bw.bb1 - 1) * 2)) | (1U << (((request->wValue.bw.bb1 - 1) * 2 + 1)))); + usb_device_0.endpoint_mask |= new_eps; + usb2_setup_endpoints_in_mask(new_eps); + } hydradancer_event_t event = { .type = EVENT_IN_BUFFER_AVAILABLE, .value = request->wValue.bw.bb1, diff --git a/hydradancer/firmware_hydradancer/User/usb_emulation_device.c b/hydradancer/firmware_hydradancer/User/usb_emulation_device.c index 4acd079..a73d02e 100644 --- a/hydradancer/firmware_hydradancer/User/usb_emulation_device.c +++ b/hydradancer/firmware_hydradancer/User/usb_emulation_device.c @@ -17,7 +17,6 @@ void usb_emulation_reinit(void) usb_device_set_string_descriptors(&usb_device_0, NULL); // Set the USB device parameters usb2_ep0_passthrough_enabled(true); - usb_device_set_endpoint_mask(&usb_device_0, ENDPOINT_1_RX | ENDPOINT_1_TX | ENDPOINT_2_RX | ENDPOINT_2_TX | ENDPOINT_3_RX | ENDPOINT_3_TX | ENDPOINT_4_RX | ENDPOINT_4_TX | ENDPOINT_5_RX | ENDPOINT_5_TX | ENDPOINT_6_RX | ENDPOINT_6_TX | ENDPOINT_7_RX | ENDPOINT_7_TX); usb_emulation_init_endpoints(); usb2_setup_endpoints(); usb2_set_device_address(0); @@ -110,25 +109,3 @@ void usb_emulation_init_endpoints(void) usb_device_0.endpoints.tx[7].max_burst = 0; usb_device_0.endpoints.tx[7].max_packet_size_with_burst = USB2_ENDP_1_15_MAX_PACKET_SIZE; } - -void usb_emulation_do_bus_reset(void) -{ - bsp_disable_interrupt(); - usb_device_set_usb3_device_descriptor(&usb_device_0, NULL); - usb_device_set_usb2_device_descriptor(&usb_device_0, NULL); - usb_device_set_usb3_config_descriptors(&usb_device_0, NULL); - usb_device_set_usb2_config_descriptors(&usb_device_0, NULL); - usb_device_set_bos_descriptor(&usb_device_0, NULL); - usb_device_set_string_descriptors(&usb_device_0, NULL); - usb_device_set_string_descriptors(&usb_device_0, NULL); - // Set the USB device parameters - usb2_ep0_passthrough_enabled(true); - usb_device_set_endpoint_mask(&usb_device_0, ENDPOINT_1_RX | ENDPOINT_1_TX | ENDPOINT_2_RX | ENDPOINT_2_TX | ENDPOINT_3_RX | ENDPOINT_3_TX | ENDPOINT_4_RX | ENDPOINT_4_TX | ENDPOINT_5_RX | ENDPOINT_5_TX | ENDPOINT_6_RX | ENDPOINT_6_TX | ENDPOINT_7_RX | ENDPOINT_7_TX); - usb_emulation_init_endpoints(); - usb2_setup_endpoints(); - for (int i = 0; i < MAX_ENDPOINTS_SUPPORTED; ++i) - { - endp_rx_set_state(&usb_device_0, i, ENDP_STATE_ACK); - } - bsp_enable_interrupt(); -} diff --git a/hydradancer/firmware_hydradancer/User/usb_emulation_device.h b/hydradancer/firmware_hydradancer/User/usb_emulation_device.h index 577d1b3..06103dc 100644 --- a/hydradancer/firmware_hydradancer/User/usb_emulation_device.h +++ b/hydradancer/firmware_hydradancer/User/usb_emulation_device.h @@ -25,6 +25,4 @@ void usb_emulation_reinit(void); void usb_emulation_init_endpoints(void); -void usb_emulation_do_bus_reset(void); - #endif diff --git a/hydradancer/firmware_hydradancer/User/usb_emulation_handlers.h b/hydradancer/firmware_hydradancer/User/usb_emulation_handlers.h index 4c1e117..36796ac 100644 --- a/hydradancer/firmware_hydradancer/User/usb_emulation_handlers.h +++ b/hydradancer/firmware_hydradancer/User/usb_emulation_handlers.h @@ -22,8 +22,10 @@ #include "wch-ch56x-lib/USBDevice/usb20.h" #include "wch-ch56x-lib/USBDevice/usb2_utils.h" #include "wch-ch56x-lib/USBDevice/usb30.h" +#include "wch-ch56x-lib/USBDevice/usb30_utils.h" #include "wch-ch56x-lib/USBDevice/usb_descriptors.h" #include "wch-ch56x-lib/USBDevice/usb_endpoints.h" +#include "wch-ch56x-lib/USBDevice/usb_types.h" __attribute__((always_inline)) static inline void usb_emulation_endp_tx_complete(TRANSACTION_STATUS status, uint8_t endp_num) { @@ -81,28 +83,84 @@ void usb_emulation_endp7_tx_complete(TRANSACTION_STATUS status) usb_emulation_endp_tx_complete(status, 7); } +void usb_emulation_endp8_tx_complete(TRANSACTION_STATUS status); +void usb_emulation_endp8_tx_complete(TRANSACTION_STATUS status) +{ + usb_emulation_endp_tx_complete(status, 8); +} + +void usb_emulation_endp9_tx_complete(TRANSACTION_STATUS status); +void usb_emulation_endp9_tx_complete(TRANSACTION_STATUS status) +{ + usb_emulation_endp_tx_complete(status, 9); +} + +void usb_emulation_endp10_tx_complete(TRANSACTION_STATUS status); +void usb_emulation_endp10_tx_complete(TRANSACTION_STATUS status) +{ + usb_emulation_endp_tx_complete(status, 10); +} + +void usb_emulation_endp11_tx_complete(TRANSACTION_STATUS status); +void usb_emulation_endp11_tx_complete(TRANSACTION_STATUS status) +{ + usb_emulation_endp_tx_complete(status, 11); +} + +void usb_emulation_endp12_tx_complete(TRANSACTION_STATUS status); +void usb_emulation_endp12_tx_complete(TRANSACTION_STATUS status) +{ + usb_emulation_endp_tx_complete(status, 12); +} + +void usb_emulation_endp13_tx_complete(TRANSACTION_STATUS status); +void usb_emulation_endp13_tx_complete(TRANSACTION_STATUS status) +{ + usb_emulation_endp_tx_complete(status, 13); +} + +void usb_emulation_endp14_tx_complete(TRANSACTION_STATUS status); +void usb_emulation_endp14_tx_complete(TRANSACTION_STATUS status) +{ + usb_emulation_endp_tx_complete(status, 14); +} + +void usb_emulation_endp15_tx_complete(TRANSACTION_STATUS status); +void usb_emulation_endp15_tx_complete(TRANSACTION_STATUS status) +{ + usb_emulation_endp_tx_complete(status, 15); +} + bool _usb_emulation_endp0_passthrough_setup_callback(uint8_t* data); bool _usb_emulation_endp0_passthrough_setup_callback(uint8_t* data) { uint8_t* ptr = ((ep_queue_member_t*)data)->ptr; uint16_t size = ((ep_queue_member_t*)data)->size; - while (hydradancer_status.ep_out_status & (0x01 << 0)) + while (true) { + bsp_disable_interrupt(); + volatile uint16_t status = hydradancer_status.ep_out_status; + bsp_enable_interrupt(); + if (!(status & (0x01 << 0))) + break; if (start_polling) hydradancer_send_event(); - WWDG_SetCounter(0); // rearm the watchdog } hydradancer_status_set_out(0); endp_tx_set_new_buffer(&usb_device_1, endpoint_mapping[0], ptr, size); write_event(EVENT_OUT_BUFFER_AVAILABLE, 0); - while (hydradancer_status.ep_out_status & (0x01 << 0)) + while (true) { + bsp_disable_interrupt(); + volatile uint16_t status = hydradancer_status.ep_out_status; + bsp_enable_interrupt(); + if (!(status & (0x01 << 0))) + break; if (start_polling) hydradancer_send_event(); - WWDG_SetCounter(0); // rearm the watchdog } return true; @@ -112,19 +170,8 @@ uint8_t usb_emulation_endp0_passthrough_setup_callback(uint8_t* ptr, uint16_t si uint8_t usb_emulation_endp0_passthrough_setup_callback(uint8_t* ptr, uint16_t size) { uint8_t* buffer = ramx_pool_alloc_bytes(ENDP_1_15_MAX_PACKET_SIZE); - if (buffer == NULL) - { - LOG_IF_LEVEL(LOG_LEVEL_CRITICAL, "usb_emulation_endp0_passthrough_setup_callback Could not allocate pool buf\r\n"); - return ENDP_STATE_NAK; - } - ep_queue_member_t* ep_queue_member = hydra_pool_get(&ep_queue); - if (ep_queue_member == NULL) - { - ramx_pool_free(buffer); - LOG_IF_LEVEL(LOG_LEVEL_CRITICAL, "usb_emulation_endp0_passthrough_setup_callback could not allocate ep_queue_member"); - return ENDP_STATE_NAK; - } memcpy(buffer, ptr, size); + ep_queue_member_t* ep_queue_member = hydra_pool_get(&ep_queue); ep_queue_member->ptr = buffer; ep_queue_member->size = size; hydra_interrupt_queue_set_next_task(_usb_emulation_endp0_passthrough_setup_callback, (uint8_t*)ep_queue_member, _ep_queue_cleanup); @@ -133,97 +180,59 @@ uint8_t usb_emulation_endp0_passthrough_setup_callback(uint8_t* ptr, uint16_t si static bool _usb_emulation_endp_rx_callback(uint8_t* data) { - ep_queue_member_t* ep_queue_member = (ep_queue_member_t*)data; - hydradancer_status_set_out(ep_queue_member->ep_num); - endp_tx_set_new_buffer(&usb_device_1, endpoint_mapping[ep_queue_member->ep_num], ep_queue_member->ptr, ep_queue_member->size); - write_event(EVENT_OUT_BUFFER_AVAILABLE, ep_queue_member->ep_num); + uint8_t endp_num = ((ep_queue_member_t*)data)->ep_num; + uint8_t* ptr = ((ep_queue_member_t*)data)->ptr; + uint16_t size = ((ep_queue_member_t*)data)->size; + + hydradancer_status_set_out(endp_num); + endp_tx_set_new_buffer(&usb_device_1, endpoint_mapping[endp_num], ptr, size); + write_event(EVENT_OUT_BUFFER_AVAILABLE, endp_num); - while (hydradancer_status.ep_out_status & (0x01 << ep_queue_member->ep_num)) + while (true) { + bsp_disable_interrupt(); + volatile uint16_t status = hydradancer_status.ep_out_status; + bsp_enable_interrupt(); + if (!(status & (0x01 << endp_num))) + { + break; + } + if (start_polling) hydradancer_send_event(); - WWDG_SetCounter(0); // rearm the watchdog } - return true; } __attribute__((always_inline)) static inline uint8_t usb_emulation_endp_rx_callback(uint8_t* const ptr, uint16_t size, uint8_t endp_num) { - if (hydradancer_status.ep_out_status & (0x01 << endp_num)) - { - return ENDP_STATE_NAK; - } - uint8_t* buffer = ramx_pool_alloc_bytes(ENDP_1_15_MAX_PACKET_SIZE); - if (buffer == NULL) + + if (endp_num == 0) { - LOG_IF_LEVEL(LOG_LEVEL_CRITICAL, "usb_emulation_endp_rx_callback could not allocate buffer\r\n"); - return ENDP_STATE_NAK; + memcpy(buffer, ptr, size); } - ep_queue_member_t* ep_queue_member = hydra_pool_get(&ep_queue); - if (ep_queue_member == NULL) + else { - ramx_pool_free(buffer); - LOG_IF_LEVEL(LOG_LEVEL_CRITICAL, "usb_emulation_endp_rx_callback could not allocate ep queue member\r\n"); - return ENDP_STATE_NAK; + usb_device_0.endpoints.rx[endp_num].buffer = buffer; } - + ep_queue_member_t* ep_queue_member = hydra_pool_get(&ep_queue); ep_queue_member->ep_num = endp_num; - ep_queue_member->ptr = ptr; + ep_queue_member->ptr = endp_num == 0 ? buffer : ptr; ep_queue_member->size = size; hydra_interrupt_queue_set_next_task(_usb_emulation_endp_rx_callback, (uint8_t*)ep_queue_member, _ep_queue_cleanup); - usb_device_0.endpoints.rx[endp_num].buffer = buffer; return ENDP_STATE_NAK; } -bool _usb_emulation_endp0_rx_callback(uint8_t* data); -bool _usb_emulation_endp0_rx_callback(uint8_t* data) +void usb2_out_nak(uint8_t endp); +void usb2_out_nak(uint8_t endp) { - hydradancer_status_set_out(0); - - uint8_t* ptr = ((ep_queue_member_t*)data)->ptr; - uint16_t size = ((ep_queue_member_t*)data)->size; - - endp_tx_set_new_buffer(&usb_device_1, endpoint_mapping[0], ptr, size); - write_event(EVENT_OUT_BUFFER_AVAILABLE, 0); - - while (hydradancer_status.ep_out_status & (0x01 << 0)) - { - if (start_polling) - hydradancer_send_event(); - WWDG_SetCounter(0); // rearm the watchdog - } - - return true; } uint8_t usb_emulation_endp0_rx_callback(uint8_t* const ptr, uint16_t size); uint8_t usb_emulation_endp0_rx_callback(uint8_t* const ptr, uint16_t size) { - if (hydradancer_status.ep_out_status & (0x01 << 0)) - { - return ENDP_STATE_NAK; - } - - uint8_t* buffer = ramx_pool_alloc_bytes(ENDP_1_15_MAX_PACKET_SIZE); - if (buffer == NULL) - { - LOG_IF_LEVEL(LOG_LEVEL_CRITICAL, "usb_emulation_endp0_passthrough_setup_callback Could not allocate pool buf\r\n"); - return ENDP_STATE_NAK; - } - ep_queue_member_t* ep_queue_member = hydra_pool_get(&ep_queue); - if (ep_queue_member == NULL) - { - ramx_pool_free(buffer); - LOG_IF_LEVEL(LOG_LEVEL_CRITICAL, "usb_emulation_endp0_passthrough_setup_callback could not allocate ep_queue_member"); - return ENDP_STATE_NAK; - } - memcpy(buffer, ptr, size); - ep_queue_member->ptr = buffer; - ep_queue_member->size = size; - hydra_interrupt_queue_set_next_task(_usb_emulation_endp0_rx_callback, (uint8_t*)ep_queue_member, _ep_queue_cleanup); - return ENDP_STATE_NAK; + return usb_emulation_endp_rx_callback(ptr, size, 0); } uint8_t usb_emulation_endp1_rx_callback(uint8_t* const ptr, uint16_t size); @@ -265,6 +274,54 @@ uint8_t usb_emulation_endp7_rx_callback(uint8_t* const ptr, uint16_t size) return usb_emulation_endp_rx_callback(ptr, size, 7); } +uint8_t usb_emulation_endp8_rx_callback(uint8_t* const ptr, uint16_t size); +uint8_t usb_emulation_endp8_rx_callback(uint8_t* const ptr, uint16_t size) +{ + return usb_emulation_endp_rx_callback(ptr, size, 8); +} + +uint8_t usb_emulation_endp9_rx_callback(uint8_t* const ptr, uint16_t size); +uint8_t usb_emulation_endp9_rx_callback(uint8_t* const ptr, uint16_t size) +{ + return usb_emulation_endp_rx_callback(ptr, size, 9); +} + +uint8_t usb_emulation_endp10_rx_callback(uint8_t* const ptr, uint16_t size); +uint8_t usb_emulation_endp10_rx_callback(uint8_t* const ptr, uint16_t size) +{ + return usb_emulation_endp_rx_callback(ptr, size, 10); +} + +uint8_t usb_emulation_endp11_rx_callback(uint8_t* const ptr, uint16_t size); +uint8_t usb_emulation_endp11_rx_callback(uint8_t* const ptr, uint16_t size) +{ + return usb_emulation_endp_rx_callback(ptr, size, 11); +} + +uint8_t usb_emulation_endp12_rx_callback(uint8_t* const ptr, uint16_t size); +uint8_t usb_emulation_endp12_rx_callback(uint8_t* const ptr, uint16_t size) +{ + return usb_emulation_endp_rx_callback(ptr, size, 12); +} + +uint8_t usb_emulation_endp13_rx_callback(uint8_t* const ptr, uint16_t size); +uint8_t usb_emulation_endp13_rx_callback(uint8_t* const ptr, uint16_t size) +{ + return usb_emulation_endp_rx_callback(ptr, size, 13); +} + +uint8_t usb_emulation_endp14_rx_callback(uint8_t* const ptr, uint16_t size); +uint8_t usb_emulation_endp14_rx_callback(uint8_t* const ptr, uint16_t size) +{ + return usb_emulation_endp_rx_callback(ptr, size, 14); +} + +uint8_t usb_emulation_endp15_rx_callback(uint8_t* const ptr, uint16_t size); +uint8_t usb_emulation_endp15_rx_callback(uint8_t* const ptr, uint16_t size) +{ + return usb_emulation_endp_rx_callback(ptr, size, 15); +} + void usb_emulation_nak_callback(uint8_t endp_num); void usb_emulation_nak_callback(uint8_t endp_num) { @@ -292,7 +349,6 @@ void usb_emulation_usb2_device_handle_bus_reset(void) // Set the USB device parameters usb2_ep0_passthrough_enabled(true); - usb_device_set_endpoint_mask(&usb_device_0, ENDPOINT_1_RX | ENDPOINT_1_TX | ENDPOINT_2_RX | ENDPOINT_2_TX | ENDPOINT_3_RX | ENDPOINT_3_TX | ENDPOINT_4_RX | ENDPOINT_4_TX | ENDPOINT_5_RX | ENDPOINT_5_TX | ENDPOINT_6_RX | ENDPOINT_6_TX | ENDPOINT_7_RX | ENDPOINT_7_TX); for (int i = 0; i < MAX_ENDPOINTS_SUPPORTED; ++i) { diff --git a/hydradancer/tests/scripts/test_hspi_serdes.py b/hydradancer/tests/scripts/test_hspi_serdes.py index eab75d6..d5a88d7 100644 --- a/hydradancer/tests/scripts/test_hspi_serdes.py +++ b/hydradancer/tests/scripts/test_hspi_serdes.py @@ -51,8 +51,8 @@ def check(array_in): intf, find_all=True, # match the first OUT endpoint - custom_match=lambda e: \ - usb.util.endpoint_direction(e.bEndpointAddress) == \ + custom_match=lambda e: + usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN)) assert ep_in is not None diff --git a/hydradancer/tests/scripts/test_loopback.py b/hydradancer/tests/scripts/test_loopback.py index ada117a..42d4b8c 100644 --- a/hydradancer/tests/scripts/test_loopback.py +++ b/hydradancer/tests/scripts/test_loopback.py @@ -79,16 +79,16 @@ def send_next_packet(head, ep_in, ep_out, endp_max_packet_size, buffer_in, buffe intf, find_all=True, # match the first OUT endpoint - custom_match=lambda e: \ - usb.util.endpoint_direction(e.bEndpointAddress) == \ + custom_match=lambda e: + usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN)) ep_out = list(usb.util.find_descriptor( intf, # match the first OUT endpoint find_all=True, - custom_match=lambda e: \ - usb.util.endpoint_direction(e.bEndpointAddress) == \ + custom_match=lambda e: + usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT)) assert ep_in is not None diff --git a/hydradancer/tests/scripts/test_loopback_randomize_packetsize.py b/hydradancer/tests/scripts/test_loopback_randomize_packetsize.py index 03113db..5fd49f8 100644 --- a/hydradancer/tests/scripts/test_loopback_randomize_packetsize.py +++ b/hydradancer/tests/scripts/test_loopback_randomize_packetsize.py @@ -85,16 +85,16 @@ def send_next_packet(head, ep_in, ep_out, endp_max_packet_size, buffer_in, buffe intf, find_all=True, # match the first OUT endpoint - custom_match=lambda e: \ - usb.util.endpoint_direction(e.bEndpointAddress) == \ + custom_match=lambda e: + usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN)) ep_out = list(usb.util.find_descriptor( intf, # match the first OUT endpoint find_all=True, - custom_match=lambda e: \ - usb.util.endpoint_direction(e.bEndpointAddress) == \ + custom_match=lambda e: + usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT)) assert ep_in is not None diff --git a/hydradancer/tests/scripts/test_speedtest.py b/hydradancer/tests/scripts/test_speedtest.py index c0c9772..1f32b50 100644 --- a/hydradancer/tests/scripts/test_speedtest.py +++ b/hydradancer/tests/scripts/test_speedtest.py @@ -61,15 +61,15 @@ ep_in = usb.util.find_descriptor( intf, # match the first OUT endpoint - custom_match=lambda e: \ - usb.util.endpoint_direction(e.bEndpointAddress) == \ + custom_match=lambda e: + usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN) ep_out = usb.util.find_descriptor( intf, # match the first OUT endpoint - custom_match=lambda e: \ - usb.util.endpoint_direction(e.bEndpointAddress) == \ + custom_match=lambda e: + usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT) assert ep_in is not None diff --git a/hydradancer/tests/scripts/test_speedtest_one_by_one.py b/hydradancer/tests/scripts/test_speedtest_one_by_one.py index 3f54b02..7d8fb92 100644 --- a/hydradancer/tests/scripts/test_speedtest_one_by_one.py +++ b/hydradancer/tests/scripts/test_speedtest_one_by_one.py @@ -64,15 +64,15 @@ ep_in = usb.util.find_descriptor( intf, # match the first OUT endpoint - custom_match=lambda e: \ - usb.util.endpoint_direction(e.bEndpointAddress) == \ + custom_match=lambda e: + usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN) ep_out = usb.util.find_descriptor( intf, # match the first OUT endpoint - custom_match=lambda e: \ - usb.util.endpoint_direction(e.bEndpointAddress) == \ + custom_match=lambda e: + usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT) assert ep_in is not None diff --git a/submodules/wch-ch56x-lib b/submodules/wch-ch56x-lib index 25ea723..9041c32 160000 --- a/submodules/wch-ch56x-lib +++ b/submodules/wch-ch56x-lib @@ -1 +1 @@ -Subproject commit 25ea72328249146b323843a1bd6ed070d26948bc +Subproject commit 9041c3273496c99fdbcd57eb8bae53264a6e0a68