Skip to content

android: Add BTECH UV-Pro rig type - #112

Merged
punk-kaos merged 3 commits into
JS8Call-improved:masterfrom
doodlecomms:uvpro-3-rig-type
Oct 17, 2026
Merged

punk-kaos merged 3 commits into
JS8Call-improved:masterfrom
doodlecomms:uvpro-3-rig-type

Conversation

@doodlecomms

@doodlecomms doodlecomms commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Closes #62. Stacked on #110 and #111, so please review only the last commit. Tested at 96c9edd. The full list below ran on earlier builds of this branch. On the final head, which only adds small clean ups since then, I rechecked connect and one TEST each way.

Claude Code (Claude Opus 5.5) wrote this under my direction. I didn't write it and haven't reviewed it line by line, but I went through every change with Claude, I can explain what each part does, and I did all the hardware testing myself.

What
Adds "BTECH UV-Pro (Bluetooth)" to Rig Type. It's opt-in, and other rigs are unchanged.
Choosing it asks for the Nearby devices permission. The launch-time request gets dropped when it follows the mic prompt.
Receive goes through submitAudioRaw. Transmit uses the existing TX audio tap. No decoder, modulator or native changes.
PTT uses the existing monitor, so a lost Bluetooth link fails the transmit.
There's no frequency control yet; you set the frequency on the radio.

Setup

  • Pair the UV-Pro in Android Bluetooth settings if you have never done it before.
  • JS8Call → Settings → Rig Control on → Rig Type "BTECH UV-Pro (Bluetooth)", and allow Nearby devices when asked. If the prompt doesn't appear, or was denied: Android Settings → Apps → JS8Call → Permissions → Nearby devices → Allow.
  • On the radio: squelch 0. With the squelch closed the radio sends no audio, so the waterfall stays black between signals. Volume can be set to 0 with knob; it only affects the speaker, not the Bluetooth audio. TOT 60 s recommended.
  • Set the frequency on the radio; the app doesn't control it yet.

Test
UV-Pro on a Galaxy A15 (Android 16). The other station was a Baofeng UV-5R + Digirig Lite on a second A15 running the current release. Simplex 145.550 FM.
Connected; the audio device shows "UV-Pro Bluetooth". "Bluetooth is off" and the permission prompt appear as expected.
The UV-5R station decoded the UV-Pro in Normal, Fast and Turbo.
The UV-Pro decoded the UV-5R station in Normal (SNR −4 to +3 dB). The waterfall works.
Slow transmitted full 25.8 s frames, and the watchdog didn't trip. The UV-5R station didn't decode them; see the note below.
Idle for 10 minutes: the radio never keyed.
Bluetooth off mid-transmit: TX stopped 0.15 s later, and the radio unkeyed about 2 s later.
App swiped away mid-transmit: the radio unkeyed immediately.
Rig type None still works.

Not tested
Other Benshi-family radios (BTECH UV-50PRO, Vero VR-N76/N7500, Radioddity GA-5WB). They use the same protocol but are unverified.
Other Android versions.
rigctld and RTS PTT on this build.
Slow decoding.
Why Slow didn't decode (I may be misreading this): since c176b65, configuredRxSubmodes() returns 0 | 1 | 4 | 2 = 7. The engine treats submodes as a bitmask over SubmodeId { A, B, C, E, I }, so 7 enables A, B and C, but not Slow (E, 1 << 3). The log on the UV-Pro phone, which has the same line, only ever scheduled A, B and C. I left it alone because it's outside this PR, but I'm happy to send a one-line fix separately.

Happy to rework any of this. If it would help, I can record a YouTube video of it working on the radio.

doodlecomms and others added 2 commits October 14, 2026 19:54
The BTECH UV-Pro carries its audio over Bluetooth as 32 kHz mono SBC,
and Android has no public SBC codec. Add a mono 8-subband encoder and
decoder, ported from HTCommander's Apache-2.0 SBC code (which follows
libsbc), with unit tests. Not used yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Connect to the radio's "BS AOC" RFCOMM audio service, decode received
SBC audio, and send transmit audio. The radio only streams audio while
an app is also connected on its control channel, so a device-info
request is sent there first. It has no PTT command: it keys on incoming
audio and unkeys on an end-of-audio frame. Transmit audio is dropped
unless PTT is armed, and a 45 s watchdog releases it. Protocol details
from HTCommander and benlink. Not wired in yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@punk-kaos

Copy link
Copy Markdown
Contributor

Nice work on this! Nice to see some new rig support!

A few things I'd like addressed before merging:

Android 14+ permissions: UV-Pro skips the microphone permission check, but the foreground service still requires it. Either use a connectedDevice foreground service for UV-Pro or ensure the required permission is granted before starting.
Stale Bluetooth callbacks: Add session-generation checks so callbacks from disconnected or replaced sessions can't modify the current connection state.
Rapid restart handling: Prevent a new UV-Pro connection attempt until the previous connection worker has finished and released its sockets.
Audio-device selection: Only show UV-Pro as the audio input when both rig_type == "btech_uvpro" and rig_control_enabled == true; otherwise offer normal microphone inputs.
The core integration looks basically good, just need to clean up a couple things that'll cause some issues for other rigs.

Add "BTECH UV-Pro (Bluetooth)" to Rig Type. Choosing it asks for the
Nearby devices permission and reminds the user to open the squelch.
Receive audio goes to the engine through submitAudioRaw and transmit
audio comes from the existing TX audio tap, so the decoder, modulator
and native code are unchanged. PTT uses the existing monitor; a lost
Bluetooth link fails the transmit. Callbacks from a replaced session are
ignored, and a new start waits until the previous connection has closed.
Frequency is set on the radio. Closes JS8Call-improved#62.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@doodlecomms

doodlecomms commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor Author

Thanks for the review! All four are addressed in 39ebfcc (only this PR's commit changed):

  • Android 14+ permissions: UV-Pro no longer skips the microphone permission check, so the foreground service starts with RECORD_AUDIO granted.
  • Stale callbacks: each UV-Pro session gets a generation number; callbacks from a replaced session are ignored.
  • Rapid restart: a new start is refused ("UV-Pro Bluetooth is still disconnecting") until earlier UV-Pro workers have closed their sockets. The counter is shared across service instances, since stopping monitoring destroys the service.
  • Audio devices: UV-Pro is offered only when rig control is on and the rig type is UV-Pro; the Audio device summary refreshes when rig control is toggled.

Also added a short hint when UV-Pro is picked: set squelch to 0, otherwise the radio sends no audio and the waterfall stays dark between signals.

Retested on the radio: mic-permission prompt, audio list with rig control on/off, rapid off/on toggling (48 starts, 17 correctly refused, no overlapping connections, no crashes), and TEST decoded both ways. also I have two different people testing this to make sure it works on other hardware besides my own

@punk-kaos

Copy link
Copy Markdown
Contributor

That looks pretty good to me, thanks for the contribution!

@punk-kaos
punk-kaos merged commit 18a27b2 into JS8Call-improved:master Oct 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for B-Tec UV-Pro/ Vero VR N 76

2 participants