Turn a DJI RC-N3 remote controller into a standard Bluetooth HID gamepad by using an Android phone as a small, read-only USB-to-Bluetooth bridge. A native macOS monitor is included for checking the connection, buttons, sticks and gimbal wheel in real time.
Experimental community project. It is not affiliated with or endorsed by DJI. Hardware support is currently limited to the verified setup below.
Android application that receives DJI RC-N2/RC-N3 controls through the upper USB-C port and exposes them to a paired computer as a standard Bluetooth HID gamepad. There is no Wi-Fi or network relay in the control path.
- Standard Bluetooth HID Gamepad; no Wi-Fi relay or companion server.
- Automatically opens when the matching RC-N3 Type-C accessory is attached.
- USB accessory is opened read-only and no DJI/DUML command is transmitted.
- Five signed 16-bit axes and eight HID button slots.
- Neutral report is sent immediately when the USB input source disappears.
- Native macOS visual monitor for connection and live input testing.
- Dependency-free Android build based on SDK command-line tools.
- Remote controller: DJI RC-N3
- Phone: Honor Play COR-AL10
- OS: HarmonyOS 2.0.0 / Android API 28
- USB role: RC-N3 is host and power source; phone is Android Open Accessory
- Accessory model:
com.dji.logiclink
AndroidManifest.xml: minimal Android application manifestsrc/com/rcn3relay/probe/MainActivity.java: automatic USB accessory entry, read-only LogicLink reader and live status UIsrc/com/rcn3relay/probe/Rcn3Decoder.java: verified 26-byte input decodersrc/com/rcn3relay/probe/BluetoothGamepad.java: Android Bluetooth HID Device registration, pairing target and automatic reconnectionsrc/com/rcn3relay/probe/HidGamepadReport.java: standard five-axis/eight-button HID gamepad descriptor and report encoderbuild.sh: dependency-free APK build using Android SDK command-line tools
- JDK 17
- Android SDK platform 28
- Android build-tools 35.0.0
The build script uses the Homebrew locations installed during hardware bring-up
by default. Override ANDROID_SDK_ROOT, JAVA_HOME, or
RCN3_PROBE_KEYSTORE when using different locations.
Safety boundary:
- Opens the Android Open Accessory file descriptor read-only.
- Creates only a
FileInputStream; it has no USBFileOutputStream. - Does not send DUML, simulator, pairing, flight, or firmware commands.
- Sends a neutral Bluetooth HID report as soon as the RC-N3 USB source stops.
- Does not synthesize input when no fresh RC-N3 frame is available.
Automatic startup:
- The manifest matches
DJI / com.dji.logiclinkwith Android'sUSB_ACCESSORY_ATTACHEDintent. - Connecting the upper RC-N3 Type-C port opens the app and starts reading.
- After the one-time Bluetooth pairing and target selection, the app registers
RC-N3 Gamepadand reconnects to the saved computer automatically. - For unattended setup, enter the Mac Bluetooth controller address shown by
macOS System Information and tap
首次配对/连接此 Mac; the address is saved.
Build:
./build.shRun the decoder and HID encoder tests:
./test.shInstall and launch over wireless ADB:
adb -s PHONE_IP:5555 install -r build/rc-n3-relay-probe.apk
adb -s PHONE_IP:5555 shell am start -n \
com.rcn3relay.probe/.MainActivityCapture logs:
adb -s PHONE_IP:5555 logcat -s RCN3Gamepad:I '*:S'Build the small native connection and input monitor:
./build-monitor.sh
open "build/RC-N3 Monitor.app"The monitor reads the standard HID Gamepad locally. A green status indicator means the phone relay is connected; pressed buttons turn green and the five axis rows move in real time. It never writes to the controller.
| RC-N3 input | HID control |
|---|---|
| Left stick horizontal / vertical | X / Y |
| Right stick horizontal / vertical | Rx / Ry |
| Left shoulder gimbal wheel | Rz |
| RTH, Fn, shutter, photo/video | Buttons 1-4 |
| C, N, S switch positions | Buttons 5-7, one-hot |
The measured raw center 1024 and endpoints 364 / 1684 are normalized to
signed 16-bit HID axes. Values within 20 raw counts of center are zeroed.
Tested on an Honor Play COR-AL10 running HarmonyOS 2.0.0 / Android API 28.
The upper RC-N3 USB-C port presents a DJI Android Open Accessory named
com.dji.logiclink. Its LogicLink records contain a 26-byte input frame.
The five little-endian 16-bit analog values start at inner-frame offsets 11, 13, 15, 17 and 19:
| Offset | Input | Center | Observed ends |
|---|---|---|---|
| 11 | Right stick horizontal | 1024 | 364 / 1684 |
| 13 | Right stick vertical | 1024 | 364 / 1684 |
| 15 | Left stick vertical | 1024 | 364 / 1684 |
| 17 | Left stick horizontal | 1024 | 364 / 1684 |
| 19 | Left shoulder gimbal wheel | 1024 | 364 / about 1672 |
Inner-frame byte 22 contains the mode switch and RTH button:
| Mask/value | Input |
|---|---|
byte22 & 0x30 == 0x20 |
Cine (C) mode |
byte22 & 0x30 == 0x10 |
Normal (N) mode |
byte22 & 0x30 == 0x00 |
Sport (S) mode |
byte22 & 0x08 != 0 |
Flight Pause/RTH button held |
Inner-frame byte 23 contains the remaining reported buttons:
| Mask | Input | Behavior |
|---|---|---|
0x01 |
Photo/Video toggle | Set for the full physical press |
0x10 |
Customizable/Fn | Short pulse; no continuous long-hold state |
0x40 |
Shutter/Record | Set for the full physical press |
Holding Fn suppresses the normal gimbal-wheel analog value. No replacement
zoom value was observed in any passively received frame; releasing Fn produces
the 0x10 pulse. A single power-button press is local to the controller and is
not reported over USB. Powering off terminates the USB read with EIO; after
powering on, the saved Android accessory permission allows reading to resume.
The input frame was observed at about 9 Hz while idle.
- Verified only with the hardware and OS versions listed above.
- The Android app uses a debug-style local signing key by default. Use your own release key before distributing production APKs.
- The RC-N3 power button is local to the controller and is not exposed as a HID button.
- The app does not control an aircraft and does not implement DJI pairing, firmware or flight commands.
Bug reports and hardware compatibility results are welcome. Please include the phone model, Android version, controller model and a sanitized log. See CONTRIBUTING.md.
Released under the MIT License.