Desktop controller for FiiO K13 R2R DAC/AMP β USB HID + Bluetooth LE.
FiiO K13 R2R Control is a native desktop application for controlling the FiiO K13 R2R DAC/AMP. It communicates with the device over USB HID (for EQ/preset management) and Bluetooth Low Energy (for input source, indicator lights, and device settings).
The BLE protocol was reverse-engineered from the official FiiO Control Android APK (v4.0.3).
USB permissions: Create
/etc/udev/rules.d/99-fiio.rules:SUBSYSTEM=="usb", ATTR{idVendor}=="2972", MODE="0666"Then run
sudo udevadm control --reload-rules && sudo udevadm trigger.
The K13 R2R is a dual-mode Bluetooth device (Classic + BLE). On Linux with Intel AX210 (and similar Intel adapters), BlueZ cannot connect BLE to dual-mode devices in the default ControllerMode = dual.
Edit /etc/bluetooth/main.conf:
# Change from:
#ControllerMode = dual
# To:
ControllerMode = le
Then restart Bluetooth:
sudo systemctl restart bluetooth
Trade-off: This disables Bluetooth Classic (A2DP audio, headset profiles). If you need Classic BT for audio devices, switch back to
dualwhen not using BLE.
This is a known BlueZ issue with Intel adapters. In dual mode, the controller's LE Coded PHY support interferes with BLE connections to dual-mode devices. The kernel has a HCI_QUIRK_BROKEN_LE_CODED quirk for this, but it doesn't fully resolve the issue for all devices.
bluetoothctl to connect41:42:F9:EB:E1:35 (BLE) vs 41:42:F9:EB:E1:60 (Classic/A2DP)git clone https://github.com/SmookeyDev/fiio-k13-control.git
cd fiio-k13-control
bun install
# Fedora
sudo dnf install rust cargo webkit2gtk4.1-devel libusb1-devel libappindicator-gtk3-devel dbus-devel
# Ubuntu/Debian
sudo apt install libwebkit2gtk-4.1-dev libusb-1.0-0-dev libappindicator3-dev libdbus-1-dev
bun run tauri dev
bun run tauri build
The K13 R2R communicates over USB HID on interface 3 using interrupt transfers (EP OUT 0x02, EP IN 0x83, Report ID 0x07).
GET: [0xBB, 0x0B, 0x00, 0x00, CMD, DATA_LEN, ...DATA, 0x00, 0xEE]
SET: [0xAA, 0x0A, 0x00, 0x00, CMD, DATA_LEN, ...DATA, 0x00, 0xEE]
BLE uses GATT service 00001100-04a5-1000-1000-40ed981a04a5 with write (1101) and notify (1102) characteristics.
Packet: [0xF1, 0x10, 0x00, LEN, CMD0, CMD1, CMD2, DATA..., 0xFF]
GET: CMD0 high nibble = 0x0X
SET: CMD0 high nibble = 0x1X (CMD0 | 0x10)
0xFFE7)0x0047)0=Peak, 1=Low Shelf, 2=High Shelf, 3=Band Pass, 4=Low Pass, 5=High Pass, 6=All Passβββββββββββββββββββββββββββββββ
β Svelte 5 Frontend β
β (Runes + SvelteKit) β
β β β
β invoke() βββΊ Tauri IPC β
βββββββββββ¬ββββββββββββββββββββ
β
βββββββββββΌββββββββββββββββββββ
β Rust Backend β
β commands.rs β
β βββ device.rs βββΊ USB β
β βββ ble_device.rs βββΊ BLEβ
βββββββββββ¬βββββββ¬βββββββββββββ
β β
βββββββββββΌβββ βββΌβββββββββββββββ
β USB HID β β BLE (btleplug) β
β (rusb) β β + D-Bus/BlueZ β
β EP 0x02/83 β β GATT 1100-04a5 β
ββββββββββββββ ββββββββββββββββββ
| Issue | Cause | Workaround |
|---|---|---|
BLE connect fails in ControllerMode = dual |
Intel AX210 + BlueZ bug with dual-mode BLE devices (bluez#577) | Set ControllerMode = le in /etc/bluetooth/main.conf |
| BLE needs 2-3 retries to connect | BlueZ GATT cache stale after failed attempts | App auto-retries with bluetoothctl remove between attempts |
| BLE connection drops after rapid commands | K13 firmware disconnects on command flood | App uses debounce and drains ACK notifications |
| Classic BT audio unavailable | ControllerMode = le disables BR/EDR |
Switch back to dual when not using BLE |
This project is licensed under the MIT License - see the LICENSE file for details.