mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-11 16:30:28 +00:00
feat: align fast-GPS beacons with MeshUI firmware (16-byte format + cadence parity)
Switch the fast-GPS beacon to the firmware's canonical 16-byte wire format (magic, key6, lat/lon microdegrees, speed km/h) — no on-wire timestamp; the receiver stamps its own RX time. Drops compatibility with the older 19-byte app format. Mirror the firmware's adaptive send cadence in the app-fallback path (LocationTrackingService): anchor + dwell motion hysteresis, EMA ground speed, 9-min stationary keepalive, fix-quality (accuracy) gate, and a post-RX hold-off to avoid channel collisions. Parked nodes now beacon the stable anchor instead of GPS wander. Add the fast_gps_region config: region-scope picker in settings backed by the firmware's fast_gps_region / fast_gps_regions custom vars. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -85,6 +85,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
double _fastLocationMovementThresholdMeters = 10.0;
|
||||
int _fastLocationActiveCadenceSeconds = 10;
|
||||
int? _fastLocationChannelIdx;
|
||||
FastGpsRegionState? _fastGpsRegionState;
|
||||
bool _rotateMapWithHeading = false;
|
||||
bool _showMapDebugInfo = false;
|
||||
bool _openMapInFullscreen = false;
|
||||
@@ -410,6 +411,58 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
_locationService.fastLocationActiveCadenceSeconds;
|
||||
_fastLocationChannelIdx = _locationService.fastLocationChannelIdx;
|
||||
});
|
||||
await _loadFastGpsRegionState();
|
||||
}
|
||||
|
||||
Future<void> _loadFastGpsRegionState() async {
|
||||
final appProvider = context.read<AppProvider>();
|
||||
FastGpsRegionState? regionState;
|
||||
try {
|
||||
regionState = await appProvider.getFastGpsRegionState();
|
||||
} catch (_) {
|
||||
regionState = null;
|
||||
}
|
||||
if (!mounted) return;
|
||||
setState(() => _fastGpsRegionState = regionState);
|
||||
}
|
||||
|
||||
Future<void> _editFastGpsRegion() async {
|
||||
final regionState = _fastGpsRegionState;
|
||||
if (regionState == null) return;
|
||||
|
||||
final selected = await showModalBottomSheet<int>(
|
||||
context: context,
|
||||
builder: (sheetContext) => SafeArea(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
for (var i = 0; i < regionState.labels.length; i++)
|
||||
ListTile(
|
||||
leading: Icon(i == 0 ? Icons.public : Icons.travel_explore),
|
||||
title: Text(regionState.labels[i]),
|
||||
trailing: regionState.selectedIndex == i
|
||||
? const Icon(Icons.check)
|
||||
: null,
|
||||
onTap: () => Navigator.pop(sheetContext, i),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (selected == null || selected == regionState.selectedIndex) return;
|
||||
try {
|
||||
await context.read<AppProvider>().setFastGpsRegion(selected);
|
||||
await _loadFastGpsRegionState();
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Failed to set region: $e'),
|
||||
backgroundColor: Colors.orange,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _setFastLocationUpdatesEnabled(bool enabled) async {
|
||||
@@ -1766,6 +1819,15 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: _editFastLocationChannel,
|
||||
),
|
||||
if (_fastGpsRegionState != null)
|
||||
ListTile(
|
||||
dense: true,
|
||||
leading: const Icon(Icons.travel_explore, size: 20),
|
||||
title: const Text('Region scope'),
|
||||
subtitle: Text(_fastGpsRegionState!.selectedLabel),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: _editFastGpsRegion,
|
||||
),
|
||||
ListTile(
|
||||
dense: true,
|
||||
leading: const Icon(Icons.send, size: 20),
|
||||
|
||||
Reference in New Issue
Block a user