# BLE Serial Bridge An Android app that connects to a BLE UART device (Nordic UART Service by default — the same service RNode firmware uses for BLE serial) and exposes it as a TCP byte pipe. With `socat` on the consuming side, that pipe becomes a real serial device node that [Reticulum](https://reticulum.network/) can use via its serial-based interfaces. ``` ┌─────────────┐ BLE/GATT ┌──────────────────┐ TCP ┌──────────────────────┐ │ BLE device │◄────────────►│ BLE Serial Bridge │◄───────►│ socat → pty │ │ (NUS UART, │ │ (this app, │ :7777 │ → rnsd / picocom / │ │ RNode, …) │ │ foreground svc) │ │ anything serial │ └─────────────┘ └──────────────────┘ └──────────────────────┘ ``` No root required anywhere. The consumer can be Termux on the same phone (loopback) or a PC on the same network (enable "Allow LAN"). ## Usage 1. Install and open the app, grant Bluetooth (and notification) permissions. 2. If the device requires bonding (RNode BLE does — it displays a pairing PIN), pair it once in Android's Bluetooth settings first. 3. Set the TCP port (default `7777`). Leave "Allow LAN" off for Termux-on-the-same-phone use; turn it on to serve a PC over WiFi. 4. The UUID fields are pre-filled with Nordic UART Service. Change them only for devices with a custom UART-style service. 5. Tap **Scan**, then tap your device. The bridge starts as a foreground service and auto-reconnects if the BLE link drops. The TCP server accepts one client at a time; a new connection displaces the old one, so a restarted `socat` reconnects cleanly. ## Reticulum on the same phone (Termux) ```sh pkg install socat socat -d pty,link=$HOME/ttyBLE0,raw,echo=0 tcp:127.0.0.1:7777 ``` Then point an RNS interface at the pty. For an RNode over BLE: ```ini [[RNode BLE]] type = RNodeInterface enabled = true port = /data/data/com.termux/files/home/ttyBLE0 frequency = 867200000 bandwidth = 125000 txpower = 7 spreadingfactor = 8 codingrate = 5 ``` For a generic KISS TNC behind a BLE UART: ```ini [[BLE KISS]] type = KISSInterface enabled = true port = /data/data/com.termux/files/home/ttyBLE0 speed = 115200 ``` (`speed` is required by pyserial but meaningless here — the BLE link ignores it.) Run `socat` and `rnsd` together, e.g. in two Termux sessions or under a process supervisor. Disable Android battery optimization for both this app and Termux, or the OS will kill the bridge. ## Reticulum on a PC (phone as BLE radio bridge) Enable "Allow LAN" in the app, then on the PC: ```sh socat -d pty,link=/tmp/ttyBLE0,raw,echo=0 tcp::7777 ``` and use `/tmp/ttyBLE0` as the `port` in the RNS interface config as above. To get a system-style name, run socat as root with `pty,link=/dev/ttyBLE0,raw,echo=0`. Note: "Allow LAN" binds to all interfaces with no authentication or encryption — anyone on the network can talk to your radio. Use it only on networks you trust. ## Sanity check without Reticulum ```sh socat -d pty,link=/tmp/ttyBLE0,raw,echo=0 tcp::7777 & picocom /tmp/ttyBLE0 ``` ## Building Requires the Android SDK (API 36) and JDK 17+. ```sh gradle assembleDebug adb install app/build/outputs/apk/debug/app-debug.apk ``` ## Design notes - **BLE side**: GATT central. Negotiates the largest MTU it can (up to 517), chunks writes to MTU−3, serializes them (one write in flight), and uses write-without-response when the characteristic supports it. Notifications on the RX characteristic feed the TCP side. Reconnects every 3 s if the link drops, for as long as the bridge is running. - **TCP side**: plain byte stream, no framing, no RFC 2217 — the BLE link has no baud rate to negotiate. `TCP_NODELAY` is set to keep KISS frame latency down. - **Defaults**: Nordic UART Service `6e400001-…`, write `6e400002-…`, notify `6e400003-…` — matches RNode BLE and most BLE-UART firmware (Adafruit, Espruino, many ESP32 sketches).