# ERTOtech Refleks Lite Arcade Stick This directory contains the hardware and firmware files for the ERTOtech Refleks Lite arcade stick project. ```text codespid/ ├── ArcadeStick_hardware/ PCB and hardware design files └── arcadestick_software/ STM32 firmware, bootloader, and USB code ``` ## Architecture The board uses an STM32F103RBT6. Its 128 KB flash is divided into three regions: | Region | Start address | Size | USB VID:PID | | --- | ---: | ---: | --- | | Bootloader / DFU | `0x08000000` | 24 KB | `1209:E667` | | App1 / XInput | `0x08006000` | 52 KB | `1209:E668` | | App2 / DInput | `0x08013000` | 52 KB | `1209:E669` | The USB manufacturer string is `ERTOtech`. ## Boot and firmware selection The bootloader runs after every reset, reads the slide switch, and jumps to the selected application's vector table. The current electrical switch logic is: - `PA4 LOW`, `PA5 HIGH`: run XInput App1. - `PA4 HIGH`, `PA5 LOW`: run DInput App2. - If both inputs have the same level, the selection is invalid and DFU starts. - Holding `START` during reset starts DFU regardless of the switch position. - If the selected application's stack pointer or reset vector is invalid, the bootloader remains in DFU mode. When the switch is moved while an application is running, the new state must remain stable for 50 ms. USB is then stopped, the firmware waits 100 ms, and calls `NVIC_SystemReset()`. After reset, the bootloader starts the application selected by the new switch position. ## DInput application DInput runs as a standard USB HID game pad. Its input report is 9 bytes: ```text Bytes 0..1: 11 buttons plus padding Byte 2: 4-bit hat switch plus padding Bytes 3..8: X, Y, Z, Rx, Ry, and Rz (unsigned 8-bit axes) ``` The neutral hat value is `8`; directions use HID hat-switch values `0..7`. The six neutral axis values are `0x80`. Physical buttons are active LOW and use GPIO pull-ups. Button 11 is present in the descriptor but is not connected to a physical input. The DInput USB configuration contains three interfaces: | Interface | Purpose | Endpoints | Behavior | | --- | --- | --- | --- | | IF0 | Gamepad HID | `0x81` IN | Functional 9-byte input reports | | IF1 | Setup HID | `0x82` IN, `0x02` OUT | Compatibility stub | | IF2 | Raw HID | `0x83` IN | Compatibility stub | The Setup and Raw report descriptors match the original device layout, but the original configuration protocol is not implemented. Unsupported control requests are stalled, unused IN endpoints remain at NAK, and Setup OUT data is accepted and discarded. ## XInput application XInput uses a vendor-specific Xbox 360 wired-controller interface: ```text Interface class : 0xFF Interface subclass : 0x5D Interface protocol : 0x01 IN endpoint : 0x81, interrupt, 64 bytes OUT endpoint : 0x02, interrupt, 64 bytes Input report : 20 bytes ``` The 20-byte input report carries the D-pad, Start, Back, A/B/X/Y, LB/RB, and digital LT/RT values. LT and RT send `0xFF` while pressed and `0x00` while released. Eight-byte rumble packets received through the OUT endpoint are parsed and the left/right motor values are stored. Unless motor outputs are connected, those values remain software-only. The XInput configuration also exposes Setup HID on IF1 (`0x83` IN and `0x03` OUT) and Raw HID on IF2 (`0x84` IN). These are compatibility stubs with the same behavior described for DInput. There are no Microsoft OS, compatible-ID, `MSFT100`, or WinUSB descriptors in the XInput application. Windows currently binds IF0 to `xusb22.inf` by its class/subclass/protocol match. Xbox console authentication is not implemented; the target is Windows/PC. ## GPIO mapping All arcade inputs are active LOW and configured with pull-ups. | Function | Pin | | --- | --- | | Up | PC0 | | Down | PC1 | | Right | PC2 | | Left | PC3 | | A | PC4 | | B | PC5 | | Y | PC6 | | X | PC7 | | RB | PC8 | | RT | PC9 | | LB | PC10 | | LT | PC11 | | Start | PC14 | | Select / Back | PA2 | | Switch input 1 | PA4 | | Switch input 2 | PA5 | | USB D- | PA11 | | USB D+ | PA12 | ## Building The project uses the VS Code STM32Cube and CMake tools. In VS Code, press `Ctrl+Shift+B` and run `CMake: build` to build the bootloader, both applications, and the combined package. The CMake presets can also be used from a terminal: ```powershell cube-cmake --preset Debug cube-cmake --build --preset Debug cube-cmake --preset Release cube-cmake --build --preset Release ``` Main CMake targets: | Target | Description | | --- | --- | | `arcadestick_bootloader` | USB DFU bootloader | | `arcadestick_xinput` | App1 XInput firmware | | `arcadestick` | App2 DInput firmware | | `arcadestick_package` | Combines all three firmware images into one BIN/HEX | Each firmware target produces `.elf`, `.hex`, and `.bin` files. ## Initial programming For a blank MCU, program the following combined image with an ST-Link: ```text arcadestick_software/build/Release/arcadestick_full.hex ``` This HEX contains the bootloader, XInput App1, and DInput App2 at their correct flash addresses. The combined BIN is exactly 128 KB: ```text arcadestick_software/build/Release/arcadestick_full.bin ``` ## Updating with USB DFU To enter DFU, hold `START` while resetting the board. The USB device appears as `ERTOtech Refleks Lite DFU` with VID:PID `1209:E667`. The bootloader uses standard DFU 1.1 and does not use DfuSe address commands. Select the destination firmware with the alternate interface number: ```powershell # Update XInput App1 dfu-util -d 1209:e667 -a 0 ` -D arcadestick_software/build/Release/arcadestick_xinput.bin # Update DInput App2 dfu-util -d 1209:e667 -a 1 ` -D arcadestick_software/build/Release/arcadestick.bin ``` - `-a 0` writes only the XInput slot. - `-a 1` writes only the DInput slot. - The bootloader region cannot be written through DFU. - Data is received in 1024-byte blocks. The corresponding 1 KB flash page is erased and programmed as half-words. - A zero-length DFU packet at the end of the download completes the update. The bootloader resets after approximately 100 ms. - The slide switch's current position, not the downloaded file, determines which application runs after reset. ### Windows driver setup This DFU bootloader does not expose Microsoft OS or automatic WinUSB descriptors. On each Windows computer, WinUSB must therefore be installed once for `Refleks Lite DFU (1209:E667)` before `dfu-util` can access the device. Use Zadig as follows: 1. Start the board in DFU mode and open Zadig. 2. Select `Options > List All Devices`. 3. Select only `Refleks Lite DFU (1209:E667)`. 4. Select `WinUSB` as the target driver and click `Install Driver`. Do not replace the drivers of the XInput (`1209:E668`), DInput (`1209:E669`), ST-Link, or any other USB device. The Zadig operation is required only once per Windows computer unless the driver is later removed. `dfu-util` must also be installed and available in `PATH`. If an update is interrupted, hold `START` during reset to re-enter DFU. This simple bootloader does not provide atomic or power-fail-safe updates; do not remove power while an update is in progress. ## Debugging with VS Code The Run and Debug list contains: - `STM32: Debug Arcade Stick (ST-Link)`: DInput App2 - `STM32: Debug Arcade Stick XInput (ST-Link)`: XInput App1 - `STM32: Debug Arcade Stick Bootloader (ST-Link)`: bootloader The applications no longer begin at the start of flash. The bootloader must already be programmed before debugging App1 or App2. While debugging the bootloader, hold `START` to prevent it from jumping immediately to an app and to keep execution in `main()`. Place XInput breakpoints in `XInput_AppProcess()` in `Core/Src/xinput_app.c`. Place DInput breakpoints in `DInput_AppProcess()` in `Core/Src/dinput_app.c`. ## CubeMX code generation The main CubeMX project file is: ```text arcadestick_software/arcadestick.ioc ``` The custom DInput, XInput, and DFU classes are stored in project-owned source files. The root `CMakeLists.txt` replaces CubeMX's single-interface HID application source list with the custom composite DInput sources. No post-generation repair script is required. ## Important source files | File | Purpose | | --- | --- | | `Core/Src/bootloader_main.c` | Boot selection, app validation, and jump | | `Core/Src/main.c` | Shared app startup and switch reset control | | `Core/Src/xinput_app.c` | XInput button/report mapping | | `Core/Src/dinput_app.c` | DInput button/report mapping | | `USB_DEVICE/App/usbd_xinput.c` | Composite XInput USB class and rumble OUT handling | | `USB_DEVICE/App/usbd_dinput.c` | Composite DInput USB class | | `USB_DEVICE/App/usbd_dfu_bootloader.c` | DFU state machine and flash programming | | `STM32F103xx_FLASH.ld` | Parameterized flash/RAM linker layout | | `CMakeLists.txt` | Bootloader, App1, App2, and package targets | | `tools/package_firmware.ps1` | Creates the combined 128 KB firmware package | ## Known limitations - Do not distribute products with these PID values until they are formally assigned by pid.codes. - Xbox console authentication/security is not implemented. - The Setup and Raw HID interfaces are compatibility stubs; the original device configuration protocol is not implemented. - The XInput application does not expose Microsoft OS or compatible-ID descriptors. - DFU has no redundant image or rollback protection against power loss. - Do not confuse the switch signal names with the observed LOW pins: on the current board, XInput is `PA4 LOW` and DInput is `PA5 LOW`. ## Licensing - Project-authored firmware: MIT License - Hardware design sources: CERN-OHL-P-2.0 - STM32 HAL, CMSIS, and other third-party components: their respective upstream licenses See the root `LICENSE` file and the component-specific license files for the complete terms.