Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v1.1.2 #5

Merged
merged 4 commits into from
Jul 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
166 changes: 112 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)|

<p style="text-align: center "><em>Facedancer backends functionalities</em></p>
Expand Down Expand Up @@ -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/
Expand Down
2 changes: 1 addition & 1 deletion docs/Testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
28 changes: 13 additions & 15 deletions hydradancer/firmware_hydradancer/User/definitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))
Expand All @@ -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")));
Expand Down Expand Up @@ -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
17 changes: 16 additions & 1 deletion hydradancer/firmware_hydradancer/User/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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 =====================//
Expand Down
Loading
Loading