Open-source SRXL2 protocol library for third-party integrations (flight controllers, sensors, ESCs). Includes a bus master implementation, telemetry decoders/encoders, embedded targets (Pico, Arduino), and a real-time sniffer for decoding SRXL2 traffic on the bench.
This is a community project -- not affiliated with Spektrum or Horizon Hobby. Contributions, bug reports, and hardware testing are all welcome. If you have a Spektrum Smart ESC, receiver, or battery, your feedback is invaluable.
Hardware status: Pico embedded targets (FC slave, sniffer) validated on an Arduino Nano RP2040 Connect with a Spektrum receiver. Channel data, RSSI, and telemetry work correctly over PIO half-duplex single-pin UART. Bus Pirate 5 passive sniffing also validated. Complex receivers (AR10360T) require Forward Programming configuration and need more investigation.
.
├── libsrxl2/ Modern SRXL2 protocol stack (context-based, no globals)
├── SRXL2/ Official Spektrum library (submodule, read-only)
├── SRXL2_Master/ Legacy bus master hooks for the official library
├── fakeuart/ UDP multicast virtual UART (simulates half-duplex bus)
├── libtransport/ Abstraction over fakeuart and serial ports
├── programs/ Simulation programs
├── embedded/ Embedded targets (Pico, Arduino)
├── tests/ Test suite (11 tests)
└── SpektrumDocumentation/ Spektrum telemetry definitions (submodule)
Context-based C11 library supporting both master and slave roles. No globals, no packed struct aliasing, explicit byte-order conversion. Includes:
- srxl2.c/h -- State machine (startup, handshake, running) with event callbacks
- srxl2_packet.c/h -- Packet codec (encode/decode all SRXL2 packet types)
- srxl2_telemetry.c/h -- Telemetry payload decoder (ESC, FP_MAH, LiPo monitor, Smart Battery, RPM)
- srxl2_internal.h -- Internal context struct and constants
The official Spektrum library with a custom master implementation. Still works, but has known issues. Kept for reference and interop testing.
git clone --recursive https://github.com/iksaif/libsrxl2.git
cd libsrxl2
mkdir build && cd build
cmake .. -DBUILD_TESTS=ON
make -jctest --output-on-failureAll 11 tests cover: CRC, packet codec, telemetry decoding, master/slave state machines, interop between old and new libraries, and scenario tests.
Two sets of simulators exist -- legacy (using the official library) and new (using libsrxl2):
| Program | Library | Role | Device ID |
|---|---|---|---|
srxl2_new_master_sim |
libsrxl2 | Bus master | 0x10 |
srxl2_new_battery_sim |
libsrxl2 | Battery sensor | 0xB0 |
srxl2_master_sim |
legacy | Bus master | 0x10 |
srxl2_battery_sim |
legacy | Battery sensor | 0xB0 |
srxl2_sniffer |
libsrxl2 | Passive sniffer | -- |
Open 3 terminals:
# Terminal 1: sniffer
./build/srxl2_sniffer
# Terminal 2: master
./build/srxl2_new_master_sim
# Terminal 3: battery (can start after master -- late join works)
./build/srxl2_new_battery_simThe master discovers the battery via handshake, sends channel data every 11ms, and polls for FP_MAH telemetry. The sniffer decodes all traffic in real time.
All new programs support both simulated (fakeuart) and real (USB-to-serial) transports:
srxl2_new_master_sim [-d <name>] [-s] [-B <rate>] [-h]
srxl2_new_battery_sim [-d <name>] [-s] [-B <rate>] [-i <0xB0-0xBF>] [-h]
srxl2_sniffer [-d <name>] [-s] [-B <rate>] [-f details|json|oneline|state] [-x] [-n] [-h]
Long forms (--device, --serial, --baud, etc.) also work.
Simulation mode (default): different bus names create isolated virtual buses (UDP multicast groups).
Serial mode example:
./build/srxl2_sniffer --serial --device /dev/cu.usbserial-1420
./build/srxl2_new_master_sim --serial --device /dev/cu.usbserial-1420The sniffer and simulators can be connected to real SRXL2 hardware using a Bus Pirate 5 as a USB-to-serial bridge.
Bus Pirate 5 Spektrum Receiver
──────────── ─────────────────
VOUT (5V) ─────── VCC
GND ─────── GND
RX ─────── SRXL2 Data
The receiver needs 5V (check your receiver's specs). The BP5 VOUT can supply this for bench testing without servos. Bidirectional communication (slave/master sim) requires half-duplex TX+RX on a single wire -- this has not yet been validated with the BP5.
Connect to the BP5 CLI (e.g., tio /dev/cu.usbmodem5buspirate1):
W 5 # Enable 5V power supply
m 3 # Select UART mode (NOT HDUART -- m 4 may produce garbled data)
# Configure: 115200 baud, 8N1, no flow control, non-inverted
bridge # Enter transparent bridge mode (use -s for echo suppression)
Exit tio (Ctrl-T q), then run the sniffer or simulator on the same port.
# Detailed view with hex dump
./build/srxl2_sniffer --serial --device /dev/cu.usbmodem5buspirate1 -f details --hex
# Compact one-line format
./build/srxl2_sniffer --serial --device /dev/cu.usbmodem5buspirate1 -f oneline
# JSON output (pipe to file or jq)
./build/srxl2_sniffer --serial --device /dev/cu.usbmodem5buspirate1 -f json | tee capture.jsonl
# ncurses live state view
./build/srxl2_sniffer --serial --device /dev/cu.usbmodem5buspirate1 -f stateThe BP5 firmware must include PR #295 (UART bridge fix) for the sniffer to receive data correctly. This fix is included in BP5 firmware releases after that PR was merged.
- Use
m 3(UART), notm 4(HDUART) -- HDUART mode on the BP5 produces garbled data (byte-level corruption, no valid0xA6magic bytes). - USB latency -- Bidirectional SRXL2 through a USB-serial bridge is not feasible: the USB round-trip (~3-5ms) exceeds the SRXL2 response window within an 11ms frame. Use an embedded target (Pico, Arduino) for slave/master roles. The BP5 bridge works well for passive sniffing.
- macOS USB CDC quirk -- The serial transport uses blocking reads with
VTIMEtimeout. Non-blockingselect()does not work reliably on macOS with BP5 USB CDC ports. - Baud rate 400000 -- macOS maps 400000 to 230400 (closest standard rate), which won't work. Stick with 115200 for testing.
SRXL2 sniffer, bus master, flight controller, and battery sensor for Raspberry
Pi Pico and Arduino Nano 33 BLE. These compile libsrxl2 directly for embedded
targets -- no OS, no dependencies beyond the vendor SDK. All Pico targets use
PIO half-duplex UART on a single GPIO pin (no echo guard needed).
The FC example (fc_pico, fc_arduino) registers as a Flight Controller
(device ID 0x30) slave, receives channel data from a Spektrum receiver, and
sends back FP_MAH + RPM telemetry. The battery example (battery_pico)
simulates a 4S LiPo sensor (device ID 0xB0) with voltage sag, current drain,
and temperature rise.
See embedded/README.md for build instructions and wiring.
SRXL2 is a half-duplex UART protocol (115200 or 400000 baud):
- Startup -- 50ms quiet period
- Handshake -- Master scans default device IDs, slaves reply, master sends broadcast to enter Running
- Running -- Master sends channel data every 11ms (5.5ms at 400k), one slave replies with telemetry per frame
Key packet types:
0x21Handshake -- device discovery and baud negotiation0xCDControl Data -- RC channels + telemetry poll0x80Telemetry -- 16-byte X-Bus sensor payload0x41Bind -- bind mode management
This is a community project and contributions are welcome! Some ways to help:
- Test on real hardware -- If you have a Spektrum Smart ESC, receiver, or battery, try the sniffer or master and report what works (or doesn't)
- Port to your FC -- The libsrxl2 stack is designed to be embedded in iNav, ArduPilot, or any RTOS
- Add telemetry types -- The decoder covers ESC, FP_MAH, LiPo, RPM, and Smart Battery, but more X-Bus sensors exist
- Bug reports and PRs -- Open an issue or send a pull request
MIT License. See LICENSE.
The official SRXL2 library (SRXL2/) is MIT licensed by Horizon Hobby, LLC.