Skip to content

FlexRadio overhaul: meters HUD + auto-discovery + one-tap connect (and QTH crash fix)#329

Open
patrickrb wants to merge 19 commits into
devfrom
feat/flex-meters-all
Open

FlexRadio overhaul: meters HUD + auto-discovery + one-tap connect (and QTH crash fix)#329
patrickrb wants to merge 19 commits into
devfrom
feat/flex-meters-all

Conversation

@patrickrb

Copy link
Copy Markdown
Owner

Single PR consolidating three open PRs as requested — supersedes and closes #327, #325, #324.

1. Meters HUD (pull-down)

  • Visible "METERS ▾" tab at the top center (tap or short drag) — replaces an invisible top-edge swipe that fought the system notification-shade gesture.
  • Adapts per rig: ALC + SWR universally; power / S-meter / voltage / PA-temp on rigs that stream them (Flex/Xiegu). Per-meter toggles in Settings → Meters (SWR + ALC + PWR default on).
  • In-HUD TX-power slider for FlexRadio (0–100 W, pushed to the rig + persisted).

2. FlexRadio network connection

  • Discovery actually works: CHANGE_WIFI_MULTICAST_STATE + a MulticastLock held while the picker is open (Android was dropping the discovery broadcasts without it).
  • Live discovery list (from Flex picker: refresh discovered radios live while dialog is open #325): the picker polls the factory once a second so radios found after opening appear without reopening, rebuilding only on real changes (FlexPickerLogic) to avoid scroll resets.
  • Auto-connect when exactly one radio is found (gated: never on a stale cached entry or over a live session); manual IP is a collapsed fallback.
  • One-tap CAT connect: the Flex address is persisted, so the CAT chip near CQ reconnects to the saved rig on a cold start.
  • Connection feedback: Flex now reports success → CAT chip goes connecting→connected + a "connected" toast.

3. QTH executor crash fix (from #324)

  • Guards executor submits against a teardown race (ExecutorUtils + MainViewModel). Unrelated to the Flex/meters work — bundled here at the author's request.

Testing

  • Unit tests across all three: meter converters + enabled/available filter, clampTxPowerWatts, shouldAutoConnectFlex, FlexPickerLogic, catTapAction, ExecutorUtils. All green.
  • Built + installed on a Pixel 8; verified the METERS tab opens the sheet and (via debug log) discovery finds a real FLEX-6400 that then streams meters.

🤖 Generated with Claude Code

patrickrb and others added 13 commits June 23, 2026 11:14
afterDecode() runs on the FT8 decode thread and submits a QTH-lookup
task to getQTHThreadPool after every decode pass. That pool (and
sendWaveDataThreadPool) is shut down in MainViewModel.onCleared() when
the ViewModel is destroyed on app close or connection reset/reconnect. A
decode result landing in the same instant the pool is shut down reaches
ExecutorService.execute() on a terminated pool and throws
RejectedExecutionException on the decode thread, crashing the app
(observed on a FlexRadio network reconnect).

Add ExecutorUtils.safeExecute(), which skips submission when the pool is
shut down and swallows the residual RejectedExecutionException race,
dropping the follow-up task instead of crashing. Route all three submit
sites (QTH lookup + two network/CAT TX-audio sends) through it.

Covered by ExecutorUtilsTest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The FlexRadio network picker only refreshed its discovered-radio list via
a one-shot FlexRadioFactory event listener that fired on the first add.
Discovery typically takes a few seconds, so a radio that surfaced shortly
after the dialog opened never appeared — the user had to close and
reselect Network to get a fresh seed.

Replace the listener with a 1s poll of FlexRadioFactory.flexRadios while
the dialog is open, rebuilding the displayed list only when the
discovered set actually changes (FlexPickerLogic.identityKey/listChanged)
so the list doesn't recompose / reset scroll every tick.

Covered by FlexPickerLogicTest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A top-anchored HUD, opened by a swipe-down from the top edge anywhere in
the app, showing the two meters every supported CAT rig reports back over
the existing link: ALC and SWR. These are only measurable while keyed, so
the readout is live during TX and labelled "LAST TX" otherwise (and "no
data" until the rig has ever reported, distinguished from a legitimate 0
reading via a new meterDataReceived flag on MeterProtectionController).

Reuses the existing meter plumbing: MetersSheet observes lastAlc/lastSwr
and reuses normalizedSwrToRatio for the readout; the ALC target window and
SWR halt threshold from GeneralVariables drive the green/amber/red zones so
the HUD and the protection controller agree on what "good" means.

Decision/geometry logic (bar fraction, ALC/SWR zones, freshness, edge-open
commit rule) is extracted into pure functions in MetersDisplay.kt and unit
tested; the top-sheet scaffold mirrors FT8AFBottomSheet (slide from top,
drag-up/scrim/Back to dismiss) without touching the tested bottom sheet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The HUD only read MeterProtectionController.lastAlc/lastSwr, which is fed
solely by the serial-CAT meter path (Yaesu RM4/RM6, Kenwood, Icom, serial
Xiegu). On a network rig the HUD sat blank: a FlexRadio streams its meters
over UDP into FlexConnector.mutableMeterList, and Xiegu network into
X6100Radio.mutableMeters — neither ever reached that controller.

Make the HUD source-agnostic and adaptive:

- rememberRigMeterSamples observes whichever stream the connected rig
  produces — Flex (SWR ratio, ALC dB, power W, S-meter dBm, PA temp),
  Xiegu (SWR, ALC, power, S-meter, voltage), or the serial controller
  (ALC, SWR) — and returns the rig's available meters.
- Pure per-source converters (MetersDisplay.kt) normalize each rig's
  native units into a common MeterSample (bar fraction + readout + zone),
  so the HUD renders uniformly. Flex ALC is dB (low = good) vs the serial
  0-255 window; SWR converts from ratio or the normalized scale.
- A configurable meter set: Settings → Meters toggles each meter (SWR +
  ALC on by default, power/S-meter/voltage/temp off). The HUD shows the
  intersection of enabled and rig-available meters ("adapt per rig"), so
  an enabled meter the rig doesn't report is dropped, not shown empty.

All converters + the enabled/available filter are unit-tested.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Network rigs set TX power via flexMaxRfPower (default 10 W), pushed to the
rig at connect — but the only screen that ever showed or changed it
(FlexRadioInfoFragment's seekbar) is part of the legacy Java UI the Compose
app no longer reaches, so there was no way to see or adjust it.

Add an adjustable TX-power row at the top of the meters HUD, shown when the
connected rig supports it (FlexRadio; Xiegu uses a different scale and is
left for later). The label tracks the slider live; the value is pushed to
the radio (FlexConnector.setMaxRfPower → RFPOWER) and persisted to config on
release, not on every drag tick, to avoid spamming the network.

Default the PWR (output watts) meter on, so set-power and live output read
together on the rigs that report power; serial rigs don't report it, so
"adapt per rig" still hides it there. The 0..100 W clamp is a pure,
unit-tested helper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Selecting Network + FlexRadio dropped the user on a manual "IP Address"
field. Discovery code existed (FlexRadioFactory listens for the Flex UDP
broadcast on 4992) and the picker even rendered found radios — but the list
was always empty, so typing the IP was the only thing that worked.

Root cause: Android's Wi-Fi chip filters out incoming broadcast/multicast
packets unless an app holds a WifiManager.MulticastLock, and we never took
one (nor held the CHANGE_WIFI_MULTICAST_STATE permission needed for it). So
the discovery socket received nothing.

- Add CHANGE_WIFI_MULTICAST_STATE and acquire a MulticastLock while the Flex
  picker is open (released on dismiss, so no battery cost otherwise).
- Lead the picker with discovery: a "Searching…" state, the found radios as
  the primary list, and manual IP entry collapsed behind a link as a fallback
  (different subnet / VPN / broadcast blocked).
- Auto-connect when discovery finds exactly one radio and the user hasn't
  started typing — connect to your Flex with zero input. The decision
  (shouldAutoConnectFlex) is a pure, unit-tested one-shot.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…session

Field report: the picker "closes the instant you open it" and the rig stops
connecting. Cause: FlexRadioFactory is a singleton, so once a radio is cached,
reopening the picker seeds the list with it and the auto-connect LaunchedEffect
fired immediately — dismissing the dialog and, worse, reconnecting an
already-connected rig, which tears down the working session.

Gate auto-connect so it only fires on a genuinely fresh discovery:
- startedEmpty: the picker must have opened with no cached radios, so we never
  auto-connect to a stale singleton entry.
- rigAlreadyConnected: never reconnect over a live session.
(plus the existing single-radio / not-typing / one-shot guards.)

Also add debug.log diagnostics (multicastLock.held, seeded count, each radio
added, and connect path) so we can confirm whether discovery actually receives
the UDP broadcasts on the user's network.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
"If my Flex settings are set, I should just click the CAT button near CQ and
have it connect." Two gaps stopped that: the Flex address was never persisted,
and reconnectRig() no-ops when no connector exists yet (a cold start) — so the
CAT chip did nothing until you'd already connected once via the picker.

- Persist the Flex address (flexLastIp) whenever we connect — discovered, tapped,
  or typed — and load it at startup.
- Route the CAT chip tap (catTapAction): reconnect an existing connector if one's
  live; otherwise, on a cold start with a saved network Flex, connect straight to
  the remembered address; with nothing saved, point the user to setup.

Pure routing (catTapAction) is unit-tested.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Field test on a real FLEX-6400 exposed two bugs behind "it never found the
radio / didn't connect until I hit CAT":

1. Discovery worked (MulticastLock fine — debug.log showed the radio found in
   0.4s) but the picker kept spinning. FlexRadioFactory fires OnFlexRadioAdded
   BEFORE appending to its list, so the listener re-read an empty list and
   dropped the radio (logged "total=0"). It also meant the discoveredRadios
   count stayed 0, so auto-connect never fired. Now we include the radio handed
   to the callback (mergeDiscovered, deduped by address) — so it shows and
   auto-connect can fire.

2. The Flex connect never reported success: FlexConnector.onConnectSuccess
   didn't notify the rig state, so onConnected() (which sets CONNECTED + toasts)
   never ran — the CAT chip stayed idle and there was no confirmation. Added an
   OnConnectionResult callback; connectFlexRadioRig now sets CONNECTING up front
   and CONNECTED + a "connected" toast on success (ERROR on failure).

mergeDiscovered is pure + unit-tested.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The open gesture was an invisible 24dp strip at the very top — undiscoverable,
and it fought Android's notification-shade gesture, which owns the screen's top
edge, so the swipe often just opened the system shade ("can't get it to slide
down").

Replace it with a small visible "METERS ▾" tab centered at the top, below the
status bar (statusBarsPadding, so the system doesn't steal the gesture). It
opens the HUD on a tap or a short downward drag — whichever the user reaches
for. Verified on device: tab is visible and opens the sheet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…into feat/flex-meters-all

# Conflicts:
#	ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/ui/settings/ConnectionDialogs.kt
@codecov

codecov Bot commented Jun 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 16.32997% with 497 lines in your changes missing coverage. Please review.
✅ Project coverage is 11.77%. Comparing base (bc6c21e) to head (c11161e).

Files with missing lines Patch % Lines
...in/radio/ks3ckc/ft8af/ui/components/MetersSheet.kt 0.00% 257 Missing ⚠️
...adio/ks3ckc/ft8af/ui/settings/ConnectionDialogs.kt 0.00% 85 Missing ⚠️
...n/radio/ks3ckc/ft8af/ui/settings/MetersSettings.kt 0.00% 70 Missing ⚠️
...n/radio/ks3ckc/ft8af/ui/components/MetersSource.kt 0.00% 40 Missing ⚠️
...app/src/main/kotlin/radio/ks3ckc/ft8af/FT8AFApp.kt 0.00% 26 Missing ⚠️
.../radio/ks3ckc/ft8af/ui/components/MetersDisplay.kt 88.29% 1 Missing and 10 partials ⚠️
...n/radio/ks3ckc/ft8af/ui/settings/SettingsScreen.kt 0.00% 8 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##                dev     #329      +/-   ##
============================================
+ Coverage     11.51%   11.77%   +0.25%     
- Complexity      113      122       +9     
============================================
  Files            88       94       +6     
  Lines         12466    13016     +550     
  Branches       2230     2346     +116     
============================================
+ Hits           1435     1532      +97     
- Misses        10900    11343     +443     
- Partials        131      141      +10     
Files with missing lines Coverage Δ
.../radio/ks3ckc/ft8af/ui/components/CatStatusChip.kt 40.29% <100.00%> (+4.81%) ⬆️
...dio/ks3ckc/ft8af/ui/settings/FlexDiscoveryLogic.kt 100.00% <100.00%> (ø)
.../radio/ks3ckc/ft8af/ui/settings/FlexPickerLogic.kt 100.00% <100.00%> (ø)
...n/radio/ks3ckc/ft8af/ui/settings/SettingsScreen.kt 1.24% <0.00%> (-0.05%) ⬇️
.../radio/ks3ckc/ft8af/ui/components/MetersDisplay.kt 88.29% <88.29%> (ø)
...app/src/main/kotlin/radio/ks3ckc/ft8af/FT8AFApp.kt 0.54% <0.00%> (-0.05%) ⬇️
...n/radio/ks3ckc/ft8af/ui/components/MetersSource.kt 0.00% <0.00%> (ø)
...n/radio/ks3ckc/ft8af/ui/settings/MetersSettings.kt 0.00% <0.00%> (ø)
...adio/ks3ckc/ft8af/ui/settings/ConnectionDialogs.kt 0.00% <0.00%> (ø)
...in/radio/ks3ckc/ft8af/ui/components/MetersSheet.kt 0.00% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

patrickrb and others added 6 commits June 23, 2026 15:42
…opulates

Reported: the meters HUD shows the TX-power slider (so the Flex is connected)
but "No meter data yet" — the meter rows never populate.

Two causes:
1. The meter subscription is only sent when the METER_LIST *response* arrives at
   connect (FlexConnector's response handler) — an easily-missed path. The old
   legacy meter screen used to force it directly. Add FlexConnector.requestMeterStream()
   (unconditional meter list + sub) and call it from the HUD when it opens.
2. The Flex posts the SAME FlexMeterList instance on every update, which
   observeAsState dedupes via structural equality — so even once data flowed the
   bars wouldn't update. Poll the live (UDP-thread-mutated) instance ~4x/sec
   instead, and gate the empty state on a new FlexConnector.meterDataReceived flag
   (set on the first packet, also logged for diagnosis).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The meters appeared but didn't move. The 250ms poll tick was read *inside* the
per-rig sampler @composable, so only that child recomposed — its fresh values
never propagated to the bars rendered in MetersSheet's scope (a returned List
doesn't update the caller unless the caller recomposes).

Move the poll to MetersSheet: a produceState frame (250ms, only while the sheet
is visible) is read in the render scope and passed into rememberRigMeterSamples,
forcing it to re-run and re-read each rig's live, in-place-mutated meter values.
The per-rig readers are now plain functions so their results propagate normally.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…d gate)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A FlexRadio (network) was transmitting 0 W and the operator had to listen to
RX audio acoustically. Root cause: GeneralVariables.connectMode was left as
USB_CABLE (from a previously-attached USB sound card, even after unplugging),
and both the transmit path and onTransmitByWifi (the DAX sender) — plus the RX
source selection — are gated on connectMode == NETWORK. So TX audio went to the
stale USB output (radio transmitted silence) and RX fell back to the phone mic.

Connecting to a Flex always means network/DAX audio, so connectFlexRadioRig now
forces connectMode = NETWORK (persisted) and clears any stale USB-audio output
override. TX then streams to the Flex over DAX (real power, meters move) and RX
comes from DAX instead of the mic.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Meters intermittently showed "No meter data yet" on a connected Flex. The
subscription (requestMeterStream) only fired once, when the rig connected — and
if that raced the link coming up, it never retried, so meters never started.

Key the subscription on the HUD's visibility (active) as well as the connector,
so opening the meters HUD always (re)requests the stream. Restores a light
debug.log diagnostic (requestMeterStream call + first packet) to confirm.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fixes the Flex meter mapping and connection handling, and lays the
groundwork for DAX transmit. Meters (ALC/temp/S-meter), connection
reliability, and slice ownership are working and verified on-device;
DAX transmit now reaches the modulator but does not yet make full
power (paused — see below).

Meters / mapping (FlexMeterInfos, FlexConnector):
- Resolve the SWR/ALC/PWR/S-meter/temp meter ids deterministically from
  the full meter table (lowest id, exact-name match), so duplicate
  per-slice/per-TX-block meters can't latch ALC/S-meter onto an inactive
  duplicate. Idempotent across meter-list re-requests.

Connection reliability (FlexConnector, MainViewModel):
- Run the client/gui + slice/stream setup exactly once per logical
  connection (slicesConfigured guard, re-armed in connect()); a re-fired
  onConnectSuccess no longer re-mints the client and orphans the slice.
- reconnectRig() no-ops while CONNECTING/CONNECTED so repeated CAT-chip
  taps can't spawn parallel sessions. Guard connectFlexRadioRig against a
  duplicate connect to the same IP.

Slice ownership (FlexRadio, FlexConnector, FlexNetworkRig):
- Capture the radio-assigned slice index from the "slice create" response
  instead of hardcoding 0; configure THAT slice (DIGU/filter/DAX bind) and
  claim it as the transmit slice (slice s <n> tx=1). Band/frequency changes
  retune the owned slice.

DAX transmit audio (FlexRadio, VITA):
- Parse DAX TX stream id via long (was overflowing Integer.parseInt -> 0).
- Tag TX audio with the DAX-audio class id (0x534C03E3), TSI_UTC, and the
  correct VITA packet_size, matching the radio's own RX audio format.
- Send TX audio to the radio's VITA data port (4991).
- Enable DAX transmit (dax tx 1 + transmit set dax=1). This gets audio to
  the modulator (ALC moves off the floor), but output power is still low —
  likely the SmartSDR DAX-TX gain (a GUI/profile setting with no API
  command). Transmit is paused here pending a packet capture vs a working
  DAX app.

Test: FlexResponseSliceTest covers the slice-index parse.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR consolidates prior FlexRadio-focused work into a single change set: adds a pull-down meters HUD with per-meter settings, improves FlexRadio network discovery/auto-connect and one-tap reconnect from the CAT status chip, and hardens executor submissions to avoid a teardown race crash.

Changes:

  • Add a new meters HUD (top sheet + handle) with pure, unit-tested meter conversion/visibility logic and a dedicated Settings → Meters screen.
  • Improve FlexRadio network UX: multicast discovery reliability, live-updating picker list, gated auto-connect, and reconnect-to-saved-IP behavior from the CAT chip.
  • Fix a teardown race by guarding executor submissions, and add multiple unit tests for the new pure logic paths.

Reviewed changes

Copilot reviewed 28 out of 28 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/ui/settings/FlexPickerLogicTest.kt New unit tests for picker list identity/change detection.
ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/ui/settings/FlexDiscoveryLogicTest.kt New unit tests for Flex auto-connect gating logic.
ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/ui/components/MetersDisplayTest.kt New unit tests for meters HUD pure logic (zones, formatting, visibility, clamp).
ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/ui/components/CatStatusChipLogicTest.kt Extends tests to cover CAT chip tap routing behavior.
ft8af/app/src/test/java/com/k1af/ft8af/flex/FlexResponseSliceTest.java New unit tests for parsing slice index from Flex responses.
ft8af/app/src/test/java/com/k1af/ft8af/ExecutorUtilsTest.java New unit tests for executor submission guard.
ft8af/app/src/main/res/values/strings_compose.xml Adds strings for Flex discovery, meters HUD, and meters settings.
ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/ui/settings/SettingsScreen.kt Adds a new Settings category entry for Meters.
ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/ui/settings/MetersSettings.kt New settings screen for meter visibility toggles persisted to config.
ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/ui/settings/FlexPickerLogic.kt New pure helper for stable discovery list updates.
ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/ui/settings/FlexDiscoveryLogic.kt New pure helper for gated auto-connect decision.
ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/ui/settings/ConnectionDialogs.kt Flex picker: multicast lock, live polling, auto-connect, manual-IP fallback UI.
ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/ui/components/MetersSource.kt New rig-aware meter sampling source + Flex TX power set/persist helpers.
ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/ui/components/MetersSheet.kt New top-anchored meters sheet UI and the visible “METERS” handle.
ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/ui/components/MetersDisplay.kt New pure meters conversion/visibility logic shared across rigs.
ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/ui/components/CatStatusChip.kt Adds pure tap-action routing to enable “connect saved Flex” cold-start behavior.
ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/FT8AFApp.kt Wires meters handle/sheet overlays and updated CAT reconnect behavior.
ft8af/app/src/main/java/com/k1af/ft8af/rigs/FlexNetworkRig.java Retunes/sets mode on the app-owned slice index instead of hardcoded slice 0.
ft8af/app/src/main/java/com/k1af/ft8af/MainViewModel.java Adds safe executor submits; improves Flex connect state handling, persistence, and duplicate-connect guards.
ft8af/app/src/main/java/com/k1af/ft8af/GeneralVariables.java Adds persisted Flex last IP and meter-visibility flags.
ft8af/app/src/main/java/com/k1af/ft8af/ft8transmit/MeterProtectionController.java Adds “meterDataReceived” to distinguish real 0 vs “no data yet”.
ft8af/app/src/main/java/com/k1af/ft8af/flex/VITA.java Fixes VITA header fields/packet sizing for DAX TX compatibility.
ft8af/app/src/main/java/com/k1af/ft8af/flex/FlexRadio.java Adds fixed VITA port const; slice ownership tracking; DAX TX fixes; slice index parsing support.
ft8af/app/src/main/java/com/k1af/ft8af/flex/FlexMeterInfos.java Makes meter-id resolution deterministic to avoid latching onto duplicate/idle meters.
ft8af/app/src/main/java/com/k1af/ft8af/ExecutorUtils.java New helper to safely submit to executor pools during teardown.
ft8af/app/src/main/java/com/k1af/ft8af/database/DatabaseOpr.java Loads persisted Flex last IP and meter toggle flags from config.
ft8af/app/src/main/java/com/k1af/ft8af/connector/FlexConnector.java Adds connection result callbacks, slice/DAX setup guard, meter stream request helper, and slice index exposure.
ft8af/app/src/main/AndroidManifest.xml Adds multicast permission needed for Flex discovery reliability.
Comments suppressed due to low confidence (1)

ft8af/app/src/main/java/com/k1af/ft8af/connector/FlexConnector.java:308

  • FlexConnector.meterDataReceived is never reset for a new connection attempt. If the connector previously received meters, a later reconnect can incorrectly treat stale meter values as valid before new packets arrive (and the HUD may show “last TX” data from a prior session). Reset this flag at the start of connect().
    public void connect() {
        // Re-arm the one-time setup for this fresh connection attempt. onConnectSuccess
        // then runs the full client/gui + slice/stream setup exactly once; if it fires
        // again for the same attempt it is a no-op (no re-gui, no orphaned slice).
        slicesConfigured = false;
        super.connect();
        flexRadio.openAudio();
        flexRadio.connect();
        flexRadio.openStreamPort();
    }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 310 to 320
@Override
public void disconnect() {
super.disconnect();
// Re-arm the one-time slice setup so the next connection creates a fresh slice
// and re-discovers its index, rather than reusing stale ownership state.
slicesConfigured = false;
flexRadio.clearSliceState();
flexRadio.closeAudio();
flexRadio.closeStreamPort();
flexRadio.disConnect();
}
Comment on lines 1306 to 1312
@@ -1283,13 +1311,49 @@ public void connectFlexRadioRig(Context context, FlexRadio flexRadio) {
}
}
Comment on lines +277 to +289
val wifi = context.applicationContext
.getSystemService(android.content.Context.WIFI_SERVICE) as android.net.wifi.WifiManager
val multicastLock = wifi.createMulticastLock("ft8af-flex-discovery").apply {
setReferenceCounted(true)
runCatching { acquire() }
}
GeneralVariables.fileLog(
"FlexDiscovery: picker open, multicastLock.held=${multicastLock.isHeld}, " +
"seeded=${FlexRadioFactory.getInstance().flexRadios.size}, startedEmpty=$startedEmpty",
)
onDispose {
if (multicastLock.isHeld) runCatching { multicastLock.release() }
}
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.

2 participants