src/js/protocols/CapacitorSerial.js # Protocol adapter
This implementation creates a custom Capacitor USB Serial plugin specifically designed for the Betaflight App, replacing the patched capacitor-plugin-usb-serial with a clean, purpose-built solution.
- USB Permission Issues - Native Android permission handling works correctly
- Binary Protocol Support - Built-in hex string encoding/decoding for MSP protocol
- No Patches Required - Clean implementation without
patch-packageworkarounds - Better Device Detection - Automatic USB attach/detach events
- Simplified API - Designed specifically for Betaflight's architecture
betaflight-app/
├── android/app/src/main/java/
│ ├── betaflight/app/MainActivity.java # Registers the plugin
│ └── betaflight/app/protocols/serial/ # Native plugin source
│ ├── BetaflightSerialPlugin.java
│ └── UsbPermissionReceiver.java
│
├── src/js/protocols/
│ └── CapacitorSerial.js # Protocol adapter
│
└── android/app/src/main/res/xml/
└── device_filter.xml # USB device filters
File: android/app/src/main/java/betaflight/app/protocols/serial/BetaflightSerialPlugin.java
Key Features:
- Uses
usb-serial-for-androidlibrary (proven, mature library) - Supports all major USB-to-serial chipsets (FTDI, CP210x, CH34x, STM32, etc.)
- Automatic permission request handling
- Binary data transmission via hex strings
- Real-time data reception through event listeners
- Device attach/detach detection
Methods:
requestPermission()- Request USB device permissionsgetDevices()- Get list of permitted devicesconnect(options)- Connect to a devicedisconnect()- Disconnect from devicewrite(options)- Write hex string dataread()- Read available data as hex string
Events:
dataReceived- Emitted when data is receiveddeviceAttached- Emitted when USB device is attacheddeviceDetached- Emitted when USB device is detached
File: src/js/protocols/CapacitorSerial.js
Purpose: Protocol adapter that integrates the native plugin into Betaflight's serial architecture
Key Features:
- Implements the same interface as WebSerial, WebBluetooth, etc.
- Automatic hex string ↔ Uint8Array conversion
- Event forwarding to the serial system
- Android platform detection
Protocol Registration:
CapacitorSerial is registered in the protocol list alongside WebSerial, WebBluetooth, WebSocket, and VirtualSerial. The protocol is selected automatically for ports with the capacitor- prefix.
this._protocols = [
{ name: "webserial", instance: new WebSerial() },
{ name: "webbluetooth", instance: new WebBluetooth() },
{ name: "capacitorserial", instance: new CapacitorSerial() },
{ name: "websocket", instance: new Websocket() },
{ name: "virtual", instance: new VirtualSerial() },
];Selection Logic:
The port handler chooses the protocol based on the port path prefix, e.g. capacitor-<deviceId>. This ensures Android USB devices are routed to the CapacitorSerial implementation.
Port Handler Updates: Detects available Capacitor serial ports dynamically from the protocol layer
showCapacitorOptioncontrols UI visibility for Capacitor ports- Device list refresh includes Capacitor devices when available
- Handles attach/detach events and permission requests for Capacitor devices
Compatibility Check:
Serial protocol compatibility is determined by checkSerialSupport() in src/js/utils/checkCompatibility.js. This function returns true for Android/Capacitor environments and for browsers supporting the Web Serial API. It is used to conditionally enable CapacitorSerial in the UI and protocol selection logic.
AndroidManifest.xml:
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
<uses-feature android:name="android.hardware.usb.host" android:required="true" />device_filter.xml: Defines all supported USB devices (FTDI, STM32, CP210x, etc.)
- App launches on Android
- CapacitorSerial protocol is initialized
- Compatibility check detects Android platform
- Port handler includes Capacitor Serial in device refresh
- User requests USB permission →
requestPermission() - Android shows permission dialog for each device
- Granted devices appear in port list
- User selects device and connects →
connect(deviceId, baudRate) - Native plugin opens USB connection
- Data flows through hex string encoding/decoding
Sending (MSP request):
// JavaScript: Uint8Array → hex string
const data = new Uint8Array([0x24, 0x58, 0x00, 0x00, 0xfb]);
await serial.send(data); // CapacitorSerial protocol
// CapacitorSerial: Uint8Array → "24580000fb"
// Native: "24580000fb" → byte array → USBReceiving (MSP response):
// Native: USB → byte array → "24580d00..." hex string
// Event: dataReceived { data: "24580d00..." }
// CapacitorSerial: "24580d00..." → Uint8Array
// JavaScript: Uint8Array received via 'receive' eventVia usb-serial-for-android library:
- CDC-ACM - USB Communication Device Class
- CP210x - Silicon Labs (CP2102, CP2105, etc.)
- FTDI - Future Technology Devices (FT232, FT2232, FT4232, etc.)
- PL2303 - Prolific Technology
- CH34x - WinChipHead (CH340, CH341)
- STM32 - ST Microelectronics Virtual COM Port
- GD32 - GigaDevice Virtual COM Port
- AT32 - ArteryTek Virtual COM Port
- APM32 - Geehy APM32 Virtual COM Port
- Raspberry Pi Pico - RP2040 USB Serial
All the Betaflight-compatible devices listed in device_filter.xml.
- ❌
capacitor-plugin-usb-serialdependency - ❌
patch-packagedependency - ❌
patches/capacitor-plugin-usb-serial+0.0.6.patch
- ✅ Native Android USB serial implementation embedded inside the app module
- ✅ CapacitorSerial protocol adapter
- ✅ Enhanced port handler support
- ✅ Device filter XML configuration
- ✅ WebSerial protocol (for desktop browsers)
- ✅ WebBluetooth protocol (for Bluetooth connections)
- ✅ Overall serial architecture
- ✅ MSP protocol implementation
- ✅ User interface
- Install dependencies:
yarn install - Sync Capacitor:
npx cap sync android - Build Android app:
yarn android:run
- Connect USB OTG adapter with flight controller
- App should detect USB device attach
- Request permission should show Android dialog
- Granted device should appear in port list
- Select Capacitor Serial device from port list
- Click Connect
- Connection should establish at 115200 baud
- Status should show "Connected"
- MSP data should be sent/received correctly
- Configuration should load from flight controller
- Can read/write settings
- Can flash firmware
- Can view sensor data in real-time
- Disconnect/reconnect multiple times
- Physical device disconnect/reconnect
- No memory leaks during extended use
- Clean connection closure
Symptom: Permission dialog doesn't appear or permission denied
Solutions:
- Check
device_filter.xmlincludes your device's VID/PID - Verify AndroidManifest.xml has USB intent filter
- Check Android settings → Apps → Betaflight → Permissions
- Try manually revoking USB permissions and reconnecting
Symptom: USB device connected but not showing in port list
Solutions:
- Verify USB OTG adapter is working (test with other apps)
- Check device is in
device_filter.xml - Look for logs:
adb logcat | grep BetaflightSerial - Ensure
usb.hostfeature is declared in manifest
Symptom: Connect button pressed but connection doesn't establish
Solutions:
- Check USB cable quality (data lines, not just power)
- Try different baud rate (115200, 57600, 9600)
- Verify flight controller is powered properly
- Check for conflicting apps using USB device
Symptom: Connected but no MSP data flows
Solutions:
- Verify hex string encoding/decoding is correct
- Check event listeners are set up properly
- Monitor native logs for I/O errors
- Test with simple MSP commands first
- GitHub: mik3y/usb-serial-for-android
- Documentation: Comprehensive driver support
- License: MIT
- Plugins: https://capacitorjs.com/docs/plugins
- Android: https://capacitorjs.com/docs/android
- Custom Plugins: https://capacitorjs.com/docs/plugins/creating-plugins
- MSP Protocol: Binary protocol for flight controller communication
- Hex String Format: Two hex digits per byte (e.g., "24" = 0x24 = 36 decimal)
- Clean Implementation - No patches, no workarounds
- Better Permissions - Native Android permission handling
- Binary Protocol - Built for MSP from the ground up
- Maintainable - All code is yours to modify
- Extensible - Easy to add features or fix issues
- Documented - Comprehensive comments and documentation
- Tested - Built on proven
usb-serial-for-androidlibrary
- Testing - Comprehensive testing on various Android devices
- Documentation - User guide for Android version
- CI/CD - Automated Android builds
- Release - Beta release for Android testers
- Feedback - Gather user feedback and iterate
Created: November 2025
Author: AI Assistant for Betaflight Team
License: GPL-3.0 (same as Betaflight Configurator)