feat(lora): consume region→preset compatibility map + TINY presets (protobufs #951)#5834
feat(lora): consume region→preset compatibility map + TINY presets (protobufs #951)#5834jamesarich wants to merge 9 commits into
Conversation
…OW presets Bump org.meshtastic:protobufs to develop-SNAPSHOT to pick up the LoRa region->preset map (protobufs #951) and the two new amateur-radio modem presets. Replays the preview wiring from #5790: - libs.versions.toml -> develop-SNAPSHOT; root build.gradle.kts forces all org.meshtastic:protobufs* to the snapshot so takpacket-sdk's transitive protobufs:2.7.25 pin can't downgrade the test runtime classpath (assembleDebug/detekt miss it; test/allTests catch it). - ChannelOption: TINY_FAST/TINY_SLOW at the firmware-accurate 15.625 kHz (0.015625f); the proto's "20kHz" is padded channel spacing. - Channel.kt: TinyFast/TinySlow names + interop-critical doc. - ModelExtensions.labelRes + label_tiny_fast/label_tiny_slow strings. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add session-scoped storage for FromRadio.region_presets, mirroring the deviceUIConfig lifecycle: - RadioConfigRepository: loraRegionPresetMapFlow + set/clear. - MeshConfigHandler.handleRegionPresets -> repository setter. - FromRadioPacketHandlerImpl: dispatch region_presets to the handler. - MeshConfigFlowManagerImpl: clear the map at each handshake start. - FakeRadioConfigRepository + FakeMeshConfigHandler: test-double parity. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- core/model/RegionPresetConstraint.kt: pure helpers over LoRaRegionPresetMap — constraintFor(region) (null = unconstrained for absent map/region/OOB index), RegionPresetConstraint.isGated(isLicensed), and repairPresetFor() to snap an illegal preset to the region default. Unit-tested in LoRaRegionPresetsTest. - Channel.kt: add the firmware-exact TinyFast/TinySlow names to the interop when() (verified against firmware DisplayFormatters::getModemPresetDisplayName). - FromRadioPacketHandlerImplTest: assert region_presets dispatches to the handler. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… re-read after swap Consume the region->preset map in the LoRa config UI: - RadioConfigViewModel exposes the decoded map + localIsLicensed (from the destination node User.is_licensed, which is reliably populated — unlike userConfig, which is empty on the LoRa screen). - LoRaConfigItemList filters the preset dropdown to the region legal presets, snaps an illegal current preset to the region default on region change, and disables licensed-only presets (with an explanatory summary) unless the device is a licensed operator. Constraints apply to the local device only. - DropDownItem gains a defaulted enabled flag so individual presets render greyed/non-selectable. - R9: a local LoRa write applies live (no reboot) and may be region-swapped by the firmware, so the set ACK now triggers a LoRa re-read to reflect it. - Falls back to the full unconstrained list when the map is absent (firmware < 2.8). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…review auto-fix) - constraintFor treats an empty-presets group as unconstrained (degrade to the full list rather than an empty picker), matching the null/absent/OOB cases. - LoRaConfigItemList always keeps the current selection in the dropdown (disabled when illegal) so the field is never blank, and memoizes the item list. Drop the redundant use_preset guard already implied by the enclosing if. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nfig (review auto-fix) Rename setLoRaRegionPresetMap/clearLoRaRegionPresetMap to setLoraRegionPresetMap/clearLoraRegionPresetMap for casing parity with the loraRegionPresetMapFlow property and the existing setLoraConfig convention. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ion (review auto-fix) - Point the licensed-region summary at the real UI labels (Licensed amateur radio (Ham) in User Config) instead of invented ones. - Add tests for the handshake clear of the region-preset map and the handleRegionPresets -> repository delegation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…place (review triage) Revert the post-save LoRa re-read: it suppressed the normal save-success dialog and auto-back for local LoRa saves. A firmware region swap (e.g. EU sibling) is instead reflected when the LoRa screen is next opened, which already re-reads the device config. Also stop applying the LoRa write optimistically so the form never shows a requested-but-not-applied region. Local LoRa saves now behave like every other config save. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
📄 Docs staleness check — advisoryThis PR modifies user-facing UI source files but does not update any page under
Changed source files: What to check:
New page checklist (if adding a new doc page):
If this PR does not require a doc update (e.g., internal refactor, bug fix, test change), add the
|
🖼️ Preview staleness check — advisoryThis PR modifies UI composables but does not update any
Changed UI files: What to check:
Adding previews checklist:
If this PR does not require preview updates (e.g., logic-only change, non-visual refactor), add the |
❌ 1 Tests Failed:
View the top 1 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
Firmware now advertises which modem presets are legal in each LoRa region during the config handshake (protobufs#951 / firmware#10736). This wires the Android client to consume that map so the preset picker is constrained per region, amateur-only presets are gated, and the two new TINY presets are handled — preventing users from selecting an illegal region/preset combination.
🌟 New Features
FromRadio.region_presets(LoRaRegionPresetMap) as session-scoped state, mirroring thedeviceUIConfighandshake lifecycle (repository flow + handler dispatch + cleared on each new handshake).default_preset.TINY_FAST/TINY_SLOW(15.625 kHz).🛠️ Refactoring & Architecture
core/modelhelper (RegionPresetConstraint), unit-testable off-Compose; the UI stays declarative.DropDownItemgains a defaultedenabledflag so individual menu items can render disabled.🧹 Chores
org.meshtastic:protobufs:develop-SNAPSHOTand force the transitivetakpacket-sdkprotobufs pin to match (rootbuild.gradle.kts). Preview-only — revert with the re-pin above.Testing Performed
LoRaRegionPresetsTest(new): decode + repair + gate — null map / absent region / out-of-range index / empty group → unconstrained; legal-kept / illegal→default / default-fallback; licensed gate on/off.FromRadioPacketHandlerImplTest:region_presetsroutes to the handler.MeshConfigFlowManagerImplTest: region map cleared on new handshake.MeshConfigHandlerImplTest: handler→repository delegation.RadioConfigViewModelTest: map flow→state,localIsLicensedfrom the node, and LoRasetConfigis not applied optimistically / issues no re-read.ChannelOptionTeststays green (TINY presets mapped). FullallTests+test+detekt+spotlessCheck+assembleDebugpass locally.🤖 Generated with Claude Code