fiio-k13-control Svelte Themes

Fiio K13 Control

πŸŽ›οΈ Reverse-engineered USB HID controller for the FiiO K13 R2R DAC/AMP β€” 10-band parametric EQ, AutoEQ profiles, built with Tauri 2 + Svelte 5 + Rust

FiiO K13 R2R Control

Desktop controller for FiiO K13 R2R DAC/AMP β€” USB HID + Bluetooth LE.

License Tauri Svelte Rust Platform Status


Table of Contents

About

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).

Features

USB HID

  • 10-Band Parametric EQ β€” Frequency (20Hz–20kHz), gain (-24/+12dB), Q (0.1–10.0), 7 filter types
  • Live Frequency Response β€” Real-time EQ curve visualization
  • Preset Management β€” Factory presets + 10 user slots with custom names
  • AutoEQ Integration β€” One-click headphone correction from the AutoEQ database
  • Global Pre-Amp β€” Overall EQ gain adjustment
  • Save to Device β€” Persist settings to onboard memory

Bluetooth LE

  • Input Source β€” Switch between USB, Coaxial, Optical, Bluetooth
  • Indicator Lights β€” Control top and knob LEDs (on/off, color, mode)
  • Device Info β€” Firmware version readout
  • Auto-retry β€” Automatic connection retries with full BlueZ cache cleanup

Requirements

  • OS: Linux (tested on Fedora 43)
  • Device: FiiO K13 R2R
  • Build tools: Rust 1.70+, Node.js 18+, Bun

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.

BLE Setup (Linux)

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.

Required: Set ControllerMode to LE

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 dual when not using BLE.

Why is this needed?

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.

BLE Connection Behavior

  • The app uses D-Bus with an explicit LE transport filter to scan, then bluetoothctl to connect
  • Connection may take 2-3 automatic retries (the app handles this internally)
  • If the connection drops, the app detects it and updates the UI accordingly
  • The K13 BLE address is 41:42:F9:EB:E1:35 (BLE) vs 41:42:F9:EB:E1:60 (Classic/A2DP)

Installation

From Source

git clone https://github.com/SmookeyDev/fiio-k13-control.git
cd fiio-k13-control
bun install

Build dependencies

# 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

Development

bun run tauri dev

Production build

bun run tauri build

Usage

  1. Connect USB β€” Click "Connect USB" for EQ management
  2. Connect BLE β€” Click "Connect BLE" for input source and light control
  3. Edit EQ bands β€” Select a band, adjust frequency/gain/Q/filter type
  4. Switch presets β€” Factory or user slots from the dropdown
  5. Save settings to any of the 10 user preset slots
  6. AutoEQ β€” Search your headphone model and apply correction with one click
  7. Settings (BLE) β€” Change input source, toggle indicator lights, pick LED colors

Presets

  • Factory (read-only): Jazz, Pop, Rock, Dance, R&B, Classic, HipHop, Retro, sDamp-1, sDamp-2
  • User (editable): USER 1–10, with renameable labels
  • Bypass: Disables EQ processing entirely

Technical Details

USB HID Protocol

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 Protocol

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)

Data Encoding

  • Frequency: unsigned 16-bit BE, value in Hz
  • Gain: signed 16-bit BE, value Γ— 10 (e.g., -2.5 dB = 0xFFE7)
  • Q Factor: unsigned 16-bit BE, value Γ— 100 (e.g., 0.71 = 0x0047)
  • Filter Type: 1 byte β€” 0=Peak, 1=Low Shelf, 2=High Shelf, 3=Band Pass, 4=Low Pass, 5=High Pass, 6=All Pass

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  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 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Known Issues

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

License

This project is licensed under the MIT License - see the LICENSE file for details.

Top categories

Loading Svelte Themes